﻿unit BrowserMainFormUnit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls, StrUtils, URLMon, Math, Registry,
  CommCtrl,
  ImgList, ShellApi,
  ShlObj, TypInfo, // ShlObj for "GetFavFolder" etc, TypInfo for "SetMethodProp" etc
  WinSkinData, WinSkinStore, // Required for "vclskin"
  RzTabs, // Required for "raize"
  EwbAcc, UrlHistory, // Required for IE history
  OleCtrls, SHDocVw_EWB, EwbCore, EmbeddedWB, // Added by "EmbeddedWb"
  Res, TemporaryFormUnit, Psapi, tlhelp32,
  DateUtils,ActiveX,WbCenterFormUnit,WbExecutive_TLB;

procedure ConfigureIE();//this procedure is used outside.
function IsDebug():boolean;
Function GetUserFromWindows: string;
procedure ForceForegroundWindow(h: HWND);

const
  WM_ICONTRAY = WM_USER + 1;

type
   TBrowserInformation = record
     Name: string;
     Path: string;
     Version: string;
   end;

type
  TBrowserMainForm = class(TForm)
    RzTabControl1: TRzTabControl;
    Timer2: TTimer;
    Button2: TButton;
    BitBtn1: TBitBtn;
    BitBtn2: TBitBtn;
    BitBtn3: TBitBtn;
    BitBtn4: TBitBtn;
    Timer1: TTimer;
    BitBtn5: TBitBtn;
    Timer3: TTimer;
    BitBtn6: TBitBtn;
    Timer4: TTimer;
    Timer5: TTimer;
    Timer6: TTimer;
    ListBox1: TListBox;
    Timer7: TTimer;
    UrlHistory1: TUrlHistory;
    Edit1: TEdit;
    SkinData1: TSkinData;
    SkinStore1: TSkinStore;
    Timer8: TTimer;
    ImageList1: TImageList;
    Timer9: TTimer;
    Panel1: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    Label10: TLabel;
    Label11: TLabel;
    Label12: TLabel;
    Timer10: TTimer;
    Timer11: TTimer;
    Panel2: TPanel;
    Label13: TLabel;
    ImageList2: TImageList;
    FavWb: TEmbeddedWB;
    Timer12: TTimer;
    CheckBox1: TCheckBox;
    Edit2: TEdit;
    Label14: TLabel;
    Panel3: TPanel;
    Label15: TLabel;
    Label16: TLabel;
    Timer13: TTimer;
    Timer14: TTimer;
    Timer15: TTimer;
    Label17: TLabel;
    Panel4: TPanel;
    Label18: TLabel;
    Label19: TLabel;
    Label20: TLabel;
    Edit3: TEdit;
    Label21: TLabel;
    Label22: TLabel;
    Timer16: TTimer;
    Label23: TLabel;
    Timer18: TTimer;
    Timer19: TTimer;
    Timer20: TTimer;
    Timer21: TTimer;
    Timer17: TTimer;
    procedure GoButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure RzTabControl1Change(Sender: TObject);
    procedure RzTabControl1Close(Sender: TObject; var AllowClose: Boolean);
    procedure Timer2Timer(Sender: TObject);
    procedure ResizeWb();
    procedure FormResize(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
    procedure BitBtn2Click(Sender: TObject);
    procedure BitBtn3Click(Sender: TObject);
    procedure BitBtn4Click(Sender: TObject);
    procedure Timer3Timer(Sender: TObject);
    procedure BitBtn5Click(Sender: TObject);
    procedure BitBtn6Click(Sender: TObject);
    procedure BitBtn6MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure Timer4Timer(Sender: TObject);
    procedure Timer5Timer(Sender: TObject);
    procedure Timer6Timer(Sender: TObject);
    procedure Edit1Click(Sender: TObject);
    procedure Timer7Timer(Sender: TObject);
    procedure FormClick(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
    procedure RzTabControl1Click(Sender: TObject);
    procedure Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
    function NewTab(URL: String; IsAfterCurrentTab: Boolean):TPWB;
    {procedure WbTitleChange(ASender: TObject; const Text: WideString);}
    procedure RecordTitleInHistory(index:Integer);
    procedure FavWbBeforeNavigate2(ASender: TObject; const pDisp: IDispatch;
      var URL, Flags, TargetFrameName, PostData, Headers: OleVariant;
      var Cancel: WordBool);
    procedure RzTabControl1TabOrderChange(Sender: TObject;
      OldIndex, NewIndex: Integer);
    procedure RzTabControl1DragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure RzTabControl1EndDrag(Sender, Target: TObject; X, Y: Integer);
    procedure Timer8Timer(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure Edit1MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure Timer9Timer(Sender: TObject);
    procedure ListBox1MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure Button2MouseMove(Sender: TObject; Shift: TShiftState;
      X, Y: Integer);
    procedure Timer10Timer(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Label1Click(Sender: TObject);
    procedure Label2Click(Sender: TObject);
    procedure Label5Click(Sender: TObject);
    procedure LabelMouseEnter(Sender: TObject);
    procedure LabelMouseLeave(Sender: TObject);
    procedure BitBtn4MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Label9Click(Sender: TObject);
    procedure Label6Click(Sender: TObject);
    procedure Label7Click(Sender: TObject);
    procedure Label8Click(Sender: TObject);
    procedure Label11Click(Sender: TObject);
    procedure Label10Click(Sender: TObject);
    procedure Label12Click(Sender: TObject);
    procedure Label3Click(Sender: TObject);
    procedure Label4Click(Sender: TObject);
    procedure GetMinMaxInfo(var Msg: TWMGETMINMAXINFO);
      message WM_GETMINMAXINFO;
    procedure Timer11Timer(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure CloseAllTabs();
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure Label13Click(Sender: TObject);
    procedure Timer12Timer(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure Edit2Enter(Sender: TObject);
    procedure Label14Click(Sender: TObject);
    procedure Edit2Change(Sender: TObject);
    procedure Edit2KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure BitBtn4MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Timer13Timer(Sender: TObject);
    procedure Timer14Timer(Sender: TObject);
    procedure Timer15Timer(Sender: TObject);
    procedure Label17Click(Sender: TObject);
    procedure Timer16Timer(Sender: TObject);
    procedure Edit3Enter(Sender: TObject);
    procedure Edit3KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure Label22Click(Sender: TObject);
    procedure Label21Click(Sender: TObject);
    procedure Label20Click(Sender: TObject);
    procedure Label19Click(Sender: TObject);
    procedure Label18Click(Sender: TObject);
    procedure Label23Click(Sender: TObject);
    procedure FavWbNewWindow3(ASender: TObject; var ppDisp: IDispatch;
      var Cancel: WordBool; dwFlags: Cardinal; const bstrUrlContext,
      bstrUrl: WideString);
    procedure Timer18Timer(Sender: TObject);
    procedure Timer19Timer(Sender: TObject);
    procedure Timer20Timer(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Timer21Timer(Sender: TObject);
    procedure Timer17Timer(Sender: TObject);
  private
    TrayIconData: TNotifyIconData;
    { Private declarations }
  public
    procedure TrayMessage(var Msg: TMessage); message WM_ICONTRAY;
    procedure WMEndSession(var Message: TWMEndSession); message WM_ENDSESSION;
    procedure WMQueryEndSession(var Msg : TWMQueryEndSession) ; message WM_QueryEndSession;
    procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA;
    { Public declarations }
  end;

var
  Res: TRes;
  Form1: TBrowserMainForm;
  wb_snmax: Integer;
  LoadedFavIconUrls: array [0 .. 100] of String;
  LoadedFavIconUrls_Count: Integer;
  DefaultFavIconFile: String;
  FavIconFile: String;
  UpdateAddressBar: Boolean;
  BrowserName: String;
  IsInitFavObject: Boolean;
  IsFavWbJustDisplayed: Boolean;
  FavList: String;
  LatestFavList:TStringList;
  FavListWithoutUrl:TStringList;
  IsToReadFavWithoutUrl:boolean;
  IsAddressListShown: Boolean;
  FavFolder: String;
  FavWbUrlSignature: String;
  IsSpecialKeyInAddressEdit: Boolean;
  TranslateUrl: String;
  AddressListUrls: TStringList;
  UrlRecordedInHistory:String;
  RecentUrlInHistoryToDelete: String;
  FormRect: TRect;
  TimeForWindowInit: Integer;
  UpdatedAddress:String;
  WasMouseOutOfAddress:boolean;
  IsNewMouseEnterAddress:boolean;
  SelectedAllAddress:String;
  IsStartMaximized: Boolean;
  NavUrl: String;
  NewTabUrl: String;
  ImgList: TImageList;
  MakeWindowOutOfScreen: Boolean;
  IsHide: Boolean;
  IsFirstSystemTrayOp: Boolean;
  OldFavSearch:String;
  FavSearchItems:TStringList;
  AllowClose:boolean;
  OnlineTestFile:String;
  BrowserStartDateTime:TDateTime;
   DefaultBrowserInformation:TBrowserInformation;
   UpdatedFormCaption:String;
   IsToMakeMaxWindowOutOfScreen:boolean;
   IsBrowserStarting:boolean;
   NewTab_IsWorking:boolean;
   IExec:IWbExecutiveClass;
   NewTabTxtContent:String;

implementation

{$R *.dfm}
procedure DisplayMessage(Text: String; title: String);
begin
  MessageBox(0, PChar(Text), PChar(title), MB_ICONEXCLAMATION);
end;
function IsDebug():boolean;
begin
Result := false;
end;

function GetLoadedDllCount():integer;
var
hProcess: THandle;
hModArray: array[0..1023] of HMODULE;
cb: DWORD;
Count:Integer;
begin
 hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or
      PROCESS_VM_READ,
      False,
      GetCurrentProcessId);
 EnumProcessModules(hProcess, @hModArray, SizeOf(hModArray), cb);
 Count := cb div SizeOf(HMODULE);
 CloseHandle(hProcess);
 Result := Count;
end;
procedure WaitForAllDllLoading();
var
c1,c2:Integer;
begin
c1 := GetLoadedDllCount;
Sleep(1000);
c2 := GetLoadedDllCount;
while (c2<>c1) do
begin
  c1 := c2;
  Sleep(1000);
  c2 := GetLoadedDllCount;
end;
end;

procedure ResizeFavWb();
var
  FavPanelWidth, FavPanelHeight, FormHeight: Integer;
  r: TRect;
  distance:Integer;
begin
  distance := 8;

  FavPanelWidth := 400;
  FavPanelHeight := 0;
  // Window Rect Variables
  GetWindowRect(Form1.Handle, r); // NOTE: POS IS RELATIVE TO SCREEN
  FormHeight := r.Bottom - r.Top;
  // configure FavObjectHeight
  FavPanelHeight := FormHeight - (Form1.BitBtn6.Top + Form1.BitBtn6.Height) - 100;
  if FavPanelHeight < 0 then
    FavPanelHeight := 0;
  Form1.Panel2.Left := Form1.BitBtn6.Left + Form1.BitBtn6.Width - FavPanelWidth;
  Form1.Panel2.Top := Form1.BitBtn6.Top + Form1.BitBtn6.Height - 1;
  Form1.Panel2.Width := FavPanelWidth;
  Form1.Panel2.Height := FavPanelHeight;

  Form1.CheckBox1.Left := distance;
  Form1.CheckBox1.Top := distance;
  Form1.CheckBox1.Width := FavPanelWidth - distance*2;
  Form1.Edit2.Top := Form1.CheckBox1.Top + Form1.CheckBox1.Height + distance;
  Form1.Edit2.Left := distance;
  Form1.Label14.Left := FavPanelWidth - (Form1.Label14.Width+distance);
  Form1.Label14.Top := Form1.Edit2.Top + Form1.Edit2.Height - Form1.Label14.Height - Round((Form1.Edit2.Height - Form1.Label14.Height)/2);
  Form1.Edit2.Width := Form1.Label14.Left - distance*2;

  Form1.FavWb.Left := distance;
  Form1.FavWb.Top := Form1.Edit2.Top + Form1.Edit2.Height + distance;
  //
  //
  //After a lot of work, I found the following "if" is necessary.
  //Otherwise, FavWb is not shown.
  //I guess, it's because its height is assigned an invalid value(negative),
  //which makes the component unusable.
  if (Form1.Panel2.Height - (Form1.FavWb.Top + distance))>0 then
    Form1.FavWb.Height := Form1.Panel2.Height - (Form1.FavWb.Top + distance)
  else
    Form1.FavWb.Height := 100;
  if (Form1.Panel2.Width - distance * 2)>0 then
    Form1.FavWb.Width := Form1.Panel2.Width - distance * 2
  else
    Form1.FavWb.Width := 100;
end;



procedure RepaintStuff();
begin
  Form1.Edit1.Repaint;
  Form1.Repaint;
  Form1.RzTabControl1.Repaint;
end;

procedure ResizeStuff();
begin
  Form1.RzTabControl1.Width := Form1.Width - 5;
  Form1.RzTabControl1.Top := Form1.BitBtn1.Top + Form1.BitBtn1.Height + 2;
  Form1.RzTabControl1.Height := Form1.Height - Form1.RzTabControl1.Top - 31;

  Form1.Button2.Left := Form1.Width - Form1.Button2.Width - 9;
  Form1.BitBtn6.Left := Form1.Width - (Form1.Width - Form1.Button2.Left)
    - Form1.BitBtn4.Width + 1;
  Form1.BitBtn4.Left := Form1.Width - (Form1.Width - Form1.BitBtn6.Left)
    - Form1.BitBtn6.Width + 1;

  Form1.Edit1.Left := Form1.BitBtn3.Left + Form1.BitBtn3.Width;
  Form1.Edit1.Width := Form1.Width - (Form1.BitBtn3.Left + Form1.BitBtn3.Width)
    - (Form1.Width - Form1.BitBtn4.Left);

  ResizeFavWb();
end;


procedure Test();
begin
;
end;

procedure ShowStopOrRefreshButton();
var
  IsComplete: Boolean;
begin

  IsComplete := false;
  try
    IsComplete := (wb[Form1.RzTabControl1.TabIndex].ReadyState =
        readystate_complete);
  except
    ;
  end;

  if IsComplete then
  begin
    Form1.BitBtn3.BringToFront;
    //Problem of the following code: sometimes there is no RefreshStop button
    //Form1.BitBtn3.Show;
    //Form1.BitBtn5.Hide;
  end
  else
  begin
    Form1.BitBtn5.BringToFront;
    //Problem of the following code: sometimes there is no RefreshStop button
    //Form1.BitBtn3.Hide;
    //Form1.BitBtn5.Show;
  end;

end;

procedure DownloadFile(SourceFile, DestFile: string);
begin
  UrlDownloadToFile(nil, PChar(SourceFile), PChar(DestFile), 0, nil);
end;

function GetFavIconFile(): String;
var
  length: DWORD;
  TempPath: string;
begin
  if FavIconFile <> '' then
  begin
    Result := FavIconFile;
    Exit;
  end;
  SetLength(TempPath, MAX_PATH);
  length := GetTempPath(MAX_PATH, PChar(TempPath));
  SetLength(TempPath, length);
  FavIconFile := TempPath + 'favicon.ico'; // TempPath ends with slash
  Result := FavIconFile;
  // ShowMessage(Result);
end;

{
procedure TBrowserMainForm.WbTitleChange(ASender: TObject;
  const Text: WideString);
var
  i: Integer;
  CurrentWb: TPWB;
  d: Variant;
  AddressTitle: WideString;
begin
  CurrentWb := nil;
  for i := 0 to wb_count - 1 do
    if wb[i].Name = TWebBrowser(ASender).Name then // FIX: use TWebBrowser(ASender), instead of TWinControl(ASender) which doesn't work.
      CurrentWb := wb[i];
  if CurrentWb = nil then
    Exit;
  try // do not use "Text" which is title - sometimes it's wrong.
    d := CurrentWb.Document;
    AddressTitle := d.title;
  except
    AddressTitle := '';
  end;
  if AddressTitle = '' then
    Exit; // do not handle it if it's empty title
  if CurrentWb.LocationURL = 'about:blank' then
    Exit; // do not handle it if it's blank page
  if AddressTitle = CurrentWb.LocationURL then
    Exit; // do not handle it if it's title equal to url
  if PreviousAddressUrl = CurrentWb.LocationURL then
    Exit; // do not handle it if it's just previously handled
  PreviousAddressUrl := CurrentWb.LocationURL;
  //
  //
  // delete the most recent record of the same url in history ...
  // why? because IE can(sometimes) automatically add to history.
  // (in reality, this would be the same as deleting all. the second visit, the first is deleted; the third visit, the previous is deleted)
  // (if implement this, should delete by judging date and time)
  Form1.UrlHistory1.DeleteUrl(PWideChar(CurrentWb.LocationURL)); // this deletes all records of the same url(added to top later). WHY NOT?
  // RecentUrlInHistoryToDelete := CurrentWb.LocationURL;
  // Form1.UrlHistory1.DeleteEntries; //UrlHistory1Delete(filter of "DeleteEntries"): DateTimeToStr(Now-LastVisited) shows wrong time
  //
  //
  // now add to history.
  Form1.UrlHistory1.AddUrl(PWideChar(CurrentWb.LocationURL),
    PWideChar(AddressTitle));
  // ShowMessage('WbTitleChange:'+AddressTitle+','+CurrentWb.LocationURL);
end;
}
procedure TBrowserMainForm.RecordTitleInHistory(index:Integer);
var
AddressTitle:String;
begin
AddressTitle:=wb[index].GetTitle;
if AddressTitle = '' then
  Exit; // do not handle it if it's empty title
if wb[index].LocationURL = 'about:blank' then
  Exit; // do not handle it if it's blank page
if AddressTitle = wb[index].LocationURL then
  Exit; // do not handle it if it's title equal to url
if UrlRecordedInHistory = wb[index].LocationURL then
  Exit; // do not handle it if it's just previously handled
UrlRecordedInHistory := wb[index].LocationURL;
//DisplayMessage('TBrowserMainForm.RecordTitleInHistory - going to record','');
UrlHistory1.DeleteUrl(PWideChar(wb[index].LocationURL));
Form1.UrlHistory1.AddUrl(PWideChar(wb[index].LocationURL),
  PWideChar(AddressTitle));
end;


// ==============================================================================
// NewTab Functions
// ==============================================================================
function TBrowserMainForm.NewTab(URL: String; IsAfterCurrentTab: Boolean):TPWB;
var
  i: Integer;
  wb_index: Integer;
  newMethod: TMethod;
  Buffer: array [0 .. 2047] of Char;
  filename: String;
  id1: LongWord;
  thread1: Integer;
begin
  NewTab_IsWorking := true;

  while PreparedWbNode = nil do
  begin
    Application.ProcessMessages;
    Sleep(1);
  end;
  while not PreparedWbNode.IsReady do
  begin
    Application.ProcessMessages;
    Sleep(1);
  end;

  //handle .url file
  URL := StringReplace(URL, sLineBreak, '',[rfReplaceAll, rfIgnoreCase]);
  //The above is necessary. URL can have sLineBreak ending.
  if FileExists(URL) then
  if LowerCase(ExtractFileExt(URL)) = '.url' then
  begin
    filename := '';
    SetString(filename, Buffer,
      GetPrivateProfileString('InternetShortcut', PChar('URL'), NIL, Buffer,
      2000, PChar(URL)));
    //Change "SizeOf(Buffer)" to "2000"
    //"The SizeOf function returns the storage size, in bytes, ..."
    //"nSize [in] The size of the buffer ... in characters."
    URL := filename;
  end;

  wb_count := wb_count + 1;
  wb_snmax := wb_snmax + 1;
  // FIX: new wb_count value is used in the following "if IsAfterCurrentTab then" block
  // which initialize wb_index and moves wb elements for wb_index space
  // So, update wb_count and wb_snmax at the very start - by calling NewTab, wb_count will increase by one, no matter what.
  //
  //

  if IsAfterCurrentTab then
  begin
    wb_index := Form1.RzTabControl1.TabIndex + 1;

    for i := wb_count - 1 downto wb_index + 1 do
      wb[i] := wb[i - 1];
    //
    //
    // for i:=wb_index+1 to wb_count-1 do
    // wb[i]:=wb[i-1];
    // The above code has a really serious problem ...
    // HUGE ERROR - overwrite order problem: say wb_index=2, then this is executed: wb[3]=wb[2]; wb[4]=wb[3]; wb[5]=wb[4]; ...
    // ERROR BEHAVIOR: later tabs are all the same
    //
    //
    Form1.RzTabControl1.Tabs.Insert(wb_index);
  end
  else
  begin
    Form1.RzTabControl1.Tabs.Insert(Form1.RzTabControl1.Tabs.Count - 1);
    wb_index := Form1.RzTabControl1.Tabs.Count - 1 - 1
  end;
  Form1.RzTabControl1.Tabs.Items[wb_index].Caption := ' ';

  wb[wb_index] := PreparedWbNode;
  PreparedWbNode := nil;
  IExec.dd := nil;

  ResizeWb;

wb[wb_index].Hide;
wb[wb_index].SetSilent(true); //wb[wb_index].Silent := true; // disable javascript errors

if URL <> 'nonavigation' then
begin
  if URL = 'home' then
    wb[wb_index].GoHome
  else
    wb[wb_index].Navigate(URL);
end;

// hide all wb, then show the current one
for i := 0 to wb_count - 1 do
  wb[i].Hide();
wb[wb_index].Show;

RzTabControl1.TabIndex := wb_index;

NewTab_IsWorking := false;
end;

// ==============================================================================
// Fav Functions
// ==============================================================================
procedure HideWindow(h: HWND); // this function also moves window outside of screen.
begin

  ShowWindow(h, SW_HIDE);
  MoveWindow(h, -1024, -1024, 1, 1, true);

end;

procedure DisplayWindow(h: HWND);
begin

  ShowWindow(h, SW_SHOWNA);

end;

procedure ForceForegroundWindow(h: HWND);
// reference: http://www.tek-tips.com/faqs.cfm?fid=4262
var
  nForeThread, nAppThread: DWORD;
begin

  nForeThread := GetWindowThreadProcessId(GetForegroundWindow(), nil);
  nAppThread := GetCurrentThreadId();
  IF nForeThread <> nAppThread then
  begin
    AttachThreadInput(nForeThread, nAppThread, true);
    BringWindowToTop(h);
    // ShowWindow(h,3);//"3" means SW_MAXIMIZE - not necessary
    AttachThreadInput(nForeThread, nAppThread, false);
  end
  ELSE
  begin
    BringWindowToTop(h);
    // ShowWindow(h,3);//"3" means SW_MAXIMIZE - not necessary
  end;

end;

procedure SetTopMost(HWND: HWND);
begin

  SetWindowPos(HWND, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE);

end;

function IsPosInRect(X, Y, Left, Top, right, Bottom: Integer): Boolean;
begin

  Result := true;
  if (X < Left) then
    Result := false;
  if (X > right) then
    Result := false;
  if (Y < Top) then
    Result := false;
  if (Y > Bottom) then
    Result := false;

end;

function GetFileModDate(filename: string): Integer; // reference: http://stackoverflow.com/questions/144453/how-to-get-create-last-modified-dates-of-a-file-in-delphi
var
  F: TSearchRec;
begin
  FindFirst(filename, faAnyFile, F);
  Result := F.Time; // Time contains the time stamp of the file. It can be converted to a TDateTime value using FileDateToDateTime.
  // if you wanted a TDateTime, change the return type and use this line:
  // Result := FileDateToDatetime(F.Time); //Converts an OS timestamp value to TDateTime value.
  FindClose(F);
end;

procedure GetIEFavourites(favpath: String);
var
  searchrec: TSearchRec;
  str: TStrings;
  path, dir, filename: String;
  Buffer: array [0 .. 2047] of Char;
  found: Integer;
  FilePath: String; // modified
begin
  //str := TStringList.Create; //modified

  //Confirmed: Adding the following code will make memory usage no longer increase.
  //str.Add('1*2*3');
  //result := str;
  //exit;
  //Solution: Use global variable - LatestFavList

  try
    path := favpath + '\*.uRL';
    dir := ExtractFilepath(path);
    found := FindFirst(path, faAnyFile, searchrec);
    while found = 0 do
    begin
      FilePath := dir + searchrec.Name; // modified

      if IsToReadFavWithoutUrl then
      begin
        LatestFavList.Add(FilePath + '*' + IntToStr(searchrec.Time)
            + '*WithoutUrl');
      end
      else
      begin
        SetString(filename, Buffer,
          GetPrivateProfileString('InternetShortcut', PChar('URL'), NIL, Buffer,
            2000, PChar(dir + searchrec.Name)));
        //Change "SizeOf(Buffer)" to "2000"
        //"The SizeOf function returns the storage size, in bytes, ..."
        //"nSize [in] The size of the buffer ... in characters."
        LatestFavList.Add(FilePath + '*' + IntToStr(searchrec.Time)
          + '*' + filename); // modified
      end;

      found := FindNext(searchrec); // FindNext relies on searchrec, so cannot close it for now. FindClose: Closes a successful FindFirst file search
    end;
    FindClose(searchrec); // modified - fix the problem of mem usage increasing
    found := FindFirst(dir + '\*', faAnyFile, searchrec);
    while found = 0 do
    begin
      if ((searchrec.Attr and faDirectory) > 0)
          and (searchrec.Name <> '.')
          and (searchrec.Name <> '..') //modified
        then
        GetIEFavourites(dir + searchrec.name); // modified
      found := FindNext(searchrec); // FindNext relies on searchrec, so cannot close it for now. FindClose: Closes a successful FindFirst file search
    end;
    FindClose(searchrec);
  finally
    ;
  end;
end;

function GetFavFolder(): string;
var
  pidl: PItemIDList;
  FavPathCharArray: array [0 .. MAX_PATH] of Char;
  favpath: string;
begin
  if FavFolder <> '' then
  begin
    Result := FavFolder;
    Exit;
  end;
  SHGetSpecialFolderLocation(Form1.Handle, CSIDL_FAVORITES, pidl);
  SHGetPathFromIDList(pidl, FavPathCharArray);
  favpath := StrPas(FavPathCharArray);
  FavFolder := favpath;
  Result := favpath;
end;

procedure GetFavList();
begin
  LatestFavList.Text := '';
  GetIEFavourites(GetFavFolder);
end;

function IsFavObjectReady(): Boolean;
var
  URL: String;
begin
  URL := Form1.FavWb.LocationURL;
  if (Pos(FavWbUrlSignature, URL) > 0) and
    (Form1.FavWb.ReadyState = readystate_complete) then
    Result := true
  else
    Result := false;
end;

procedure SplitFavLine(Input: string; const Strings: TStringList) ;
var
i1,i2:integer;
begin
    Assert(Assigned(Strings)) ;
    Strings.Clear;
    i1 := Pos('*',input);
    Strings.Add(Copy(input,0,i1-1));
    i2 := PosEx('*',input,i1+1);
    Strings.Add(Copy(input,i1+1,i2-i1-1));
    Strings.Add(Copy(input,i2+1,Length(input)-i2));
end;
function GetFavIconUrl(URL:String):String;
var
SlashAfterDomain:Integer;
begin
    if (Pos('http://', URL) = 1) or (Pos('https://', URL) = 1) then
    begin
      SlashAfterDomain := PosEx('/', URL, Pos('://', URL) + 3);
      if SlashAfterDomain = 0 then
      begin
        URL := URL + '/';
        SlashAfterDomain := length(URL);
      end;
      URL := Copy(URL, 1, SlashAfterDomain);
      URL := URL + 'favicon.ico';
      Result := URL;
      exit;
    end;
    Result := 'ERROR';
    exit;
end;

type
  TMyStringList = class(TStringList)
  protected
    function CompareStrings(const S1, S2: string): Integer; override;
  end;
function TMyStringList.CompareStrings(const S1, S2: string): Integer;
begin
    if Form1.CheckBox1.Checked then
      Result := CompareText(S2, S1);//NOTE: Originally it's CompareText(S1, S2); at http://stackoverflow.com/questions/2175066/how-can-i-get-tstringlist-to-sort-differently-in-delphi
                                    //I want the biggest value first - latest first.
                                    //So I changed it to "S2, S1"
    if not Form1.CheckBox1.Checked then
      Result := CompareText(S1, S2);
end;
function AddZeroPrefix(s:String):String;
var
i:Integer;
begin
  Result := s;
  for i := 1 to 20 - Length(s) do
    Result := '0'+Result;
end;
function IsFavSearchFound(linelist:TStringList):boolean;
var
i:Integer;
s:String;
begin
if Form1.Edit2.Font.Color = clGray then
begin
  Result := true;
  exit;
end;
if Form1.Edit2.Text = '' then
begin
  Result := true;
  exit;
end;
if OldFavSearch <> Form1.Edit2.Text  then
begin
  FavSearchItems.Free;
  FavSearchItems := TStringList.Create;
  FavSearchItems.Clear;
  FavSearchItems.Delimiter := ' ';
  FavSearchItems.DelimitedText := Form1.Edit2.Text;
  FavSearchItems.Text := LowerCase(FavSearchItems.Text);
  OldFavSearch := Form1.Edit2.Text;
  //show FavSearchItems
  //The above code is verified to work on these search text:
  //'     ', '     cOm     mIc     ', 'com mic'
  //
  //s := '';
  //for i := 0 to FavSearchItems.Count - 1 do
  //  s:=s+'"'+FavSearchItems[i]+'"'+sLineBreak;
  //DisplayMessage(s,'FavSearchItems');
end;
//start searching
Result := true;
for i := 0 to FavSearchItems.Count - 1 do
begin
  //if failed to match the current SearchItem[i] in fav linelist
  if (Pos(FavSearchItems[i],LowerCase(linelist[0])) = 0) and (Pos(FavSearchItems[i],LowerCase(linelist[2])) = 0) then
  begin
    Result := false;
    break;
  end;
end;
end;
function EncodeForNoXSS(s:String):String;
begin
//http://www.w3schools.com/tags/ref_entities.asp
Result := s;
Result := StringReplace(Result, '<', '&lt;',[rfReplaceAll, rfIgnoreCase]);
Result := StringReplace(Result, '>', '&gt;',[rfReplaceAll, rfIgnoreCase]);
Result := StringReplace(Result, '"', '&quot;',[rfReplaceAll, rfIgnoreCase]);
Result := StringReplace(Result, '''', '&apos;',[rfReplaceAll, rfIgnoreCase]);
//DisplayMessage('''','EncodeForNoXSS');//confirmed - it is: '
end;
procedure UpdateFavHtml();
var
d:Variant;
f:String;
input:TStringList;
output:TMyStringList;
i:integer;
linelist:TStringList;
s:String;
begin
//init
d := Form1.FavWb.Document;
f := FavList;
input := TStringList.Create;
output := TMyStringList.Create;
linelist := TStringList.Create;
//get rid of FavFolder
f := StringReplace(f, GetFavFolder+'\', '',[rfReplaceAll, rfIgnoreCase]);
//get rid of ".url"
f := StringReplace(f, '.uRL*', '*',[rfReplaceAll, rfIgnoreCase]);
//get rid of '<', '>', and '"'
f := EncodeForNoXSS(f);//fix: this is necessary, otherwise fav can cause xss.
//DisplayMessage(f,'f');//CONFIRMED - EncodeForNoXSS works for: '"><SCRIPT>alert(1)</SCRIPT>
//init 'input'
input.Text := f;
//sort by time
if Form1.CheckBox1.Checked then
begin
  for i := 0 to input.Count - 1 do
  begin
    //DisplayMessage(input[i],'input[i]');
    SplitFavLine(input[i],linelist);
    //DisplayMessage('['+linelist[0]+']','linelist[0]');
    //DisplayMessage('['+linelist[1]+']','linelist[1]');
    //DisplayMessage('['+linelist[2]+']','linelist[2]');
    if IsFavSearchFound(linelist) then
    begin
      s := '<!-- '+AddZeroPrefix(linelist[1])+' --><a href="'+linelist[2]+'"><img id=img_'+IntToStr(i)+' style="width:16px;height:16px;border-style: none;" src="'+GetFavIconUrl(linelist[2])+'" onerror="document.getElementById(''img_'+IntToStr(i)+''').src=''doc.ico'';">'+linelist[0]+'</a><br>';
      //the "<!-- ... -->" part is for sorting
      //DisplayMessage(s,'s');
      output.Add(s);
    end;
  end;
end;
//sort by name
if not Form1.CheckBox1.Checked then
begin
  for i := 0 to input.Count - 1 do
  begin
    //DisplayMessage(input[i],'input[i]');
    SplitFavLine(input[i],linelist);
    //DisplayMessage('['+linelist[0]+']','linelist[0]');
    //DisplayMessage('['+linelist[1]+']','linelist[1]');
    //DisplayMessage('['+linelist[2]+']','linelist[2]');
    if IsFavSearchFound(linelist) then
    begin
      s := '<!-- '+linelist[0]+' --><a href="'+linelist[2]+'"><img id=img_'+IntToStr(i)+' style="width:16px;height:16px;border-style: none;" src="'+GetFavIconUrl(linelist[2])+'" onerror="document.getElementById(''img_'+IntToStr(i)+''').src=''doc.ico'';">'+linelist[0]+'</a><br>';
      //the "<!-- ... -->" part is for sorting
      //DisplayMessage(s,'s');
      output.Add(s);
    end;
  end;
end;
output.Sort;
d.getElementById('FavListDiv').innerHTML := output.Text;
//free
input.Free;
output.Free;
linelist.Free;
end;

procedure UpdateFavList();
begin
  if IsFavObjectReady = false then
    Exit;

  IsToReadFavWithoutUrl := true;
  GetFavList();
  if FavListWithoutUrl.Text <> LatestFavList.Text then
  begin
    FavListWithoutUrl.Text := LatestFavList.Text;
    IsToReadFavWithoutUrl := false;
    GetFavList();
    FavList := LatestFavList.Text;
    UpdateFavHtml();
    if IsDebug then DisplayMessage('UpdateFavList updated.','');
  end;
end;

procedure InitFavObject();
var
  FavObjectHtmPath: String;
  i: Integer;
begin
  // res.SetupBrowserEmbeddedObjects; // already done in form create
  FavObjectHtmPath := Res.FavHtm;

  if IsInitFavObject then
    Exit;
  IsInitFavObject := true;
  Form1.FavWb.Navigate(FavObjectHtmPath);
  // To make it not displayed in recent address list of history:
  // The following does not work: "flags:=$02; //NavNoHistory $02"
  // The following does not work: UrlHistory1.DeleteUrl(PWideChar(FavWb.LocationURL)) ... even with timer delay after DocumentComplete
  // It is finally achieved by filtering it out in the address list function.
  Form1.Timer6.Enabled := true;
end;

function IsCursorOnEitherObject(HWND1: HWND; HWND2: HWND): Boolean;
var
  r: TRect;
  ps: TPoint;
begin
  Result := true;
  GetCursorPos(ps);
  GetWindowRect(HWND1, r);
  if ps.X < r.Left then
    Result := false;
  if ps.X > r.right then
    Result := false;
  if ps.Y < r.Top then
    Result := false;
  if ps.Y > r.Bottom then
    Result := false;
  if Result = true then
    Exit; // fix: on _either_ object, now it's on the first object, and it's enough for true;
  Result := true; // fix: now check if it's on the second object - default result is true, set to false if outside.
  GetWindowRect(HWND2, r);
  if ps.X < r.Left then
    Result := false;
  if ps.X > r.right then
    Result := false;
  if ps.Y < r.Top then
    Result := false;
  if ps.Y > r.Bottom then
    Result := false;
end;

// ==============================================================================
// Address Bar Functions
// ==============================================================================
procedure HideAddressList();
begin

  if IsAddressListShown = true then // this might be called very frequently - FIX: only do this when it's shown
  begin
    Form1.ListBox1.Height := 0;
    Form1.ListBox1.Width := 0;
    Form1.ListBox1.ItemIndex := -1; // so when displayed next time, nothing is selected.
    IsAddressListShown := false;
  end;
end;

procedure ShowAddressList();
begin
  if IsAddressListShown = false then // this might be called very frequently - FIX: only do this when it's not shown
  begin
    Form1.ListBox1.Top := Form1.Edit1.Top + Form1.Edit1.Height;
    Form1.ListBox1.Left := Form1.Edit1.Left;
    Form1.ListBox1.Width := Form1.Edit1.Width;
    Form1.ListBox1.Height := Form1.Edit1.Height * 10;
    IsAddressListShown := true;
  end;
end;

procedure UpdateAddressList(Search: String);
var
  Total: Integer;
  i: Integer;
  URL, title: String;
  ListBoxItems:TStringList;
begin
  AddressListUrls.Free;
  AddressListUrls := TStringList.Create;
  Form1.UrlHistory1.SortField := sfLastvisited;
  Form1.UrlHistory1.SearchField := seBoth;
  Form1.UrlHistory1.SortDirection := sdDescending;
  Form1.UrlHistory1.Search := '';
  Total := Form1.UrlHistory1.Enumerate();
  //Form1.ListBox1.Items.Text := '';
  ListBoxItems := TStringList.Create;
  ListBoxItems.Text := '';
  for i := 0 to Total - 1 do
  begin
    URL := PEntry(Form1.UrlHistory1.Items[i]).URL;
    title := PEntry(Form1.UrlHistory1.Items[i]).title;
    if Search <> '' then
    begin
      // ShowMessage(FavWbUrlSignature+','+Url+','+IntToStr(Pos(FavWbUrlSignature,Url)));
      if Title <> '' then//this filters out many junk entries that are useless.
                         //Recent browsing history is added with title, by WbTitleChange.
      if (Pos(FavWbUrlSignature, URL) = 0)
      and (Pos('http://auxbrowser.com/BrowserObjects/',URL)<>1) then // filter out the record of FavWb address(which is recent)
        if (Pos(LowerCase(Search), LowerCase(URL)) > 0) or
          (Pos(LowerCase(Search), LowerCase(title)) > 0) then
        // do search by myself - TUrlHistory doesn't do it well.
        begin
          if title = '' then//this is reserved just in case we need empty-title urls again.
            ListBoxItems.Add(URL)
          else
            ListBoxItems.Add(title + ' ' + URL);
          AddressListUrls.Add(URL);
        end;
    end
    else
    begin
      // ShowMessage(FavWbUrlSignature+','+Url+','+IntToStr(Pos(FavWbUrlSignature,Url)));
      if Title <> '' then//this filters out many junk entries that are useless.
                         //Recent browsing history is added with title, by WbTitleChange.
      if (Pos(FavWbUrlSignature, URL) = 0)
      and (Pos('http://auxbrowser.com/BrowserObjects/',URL)<>1) then // filter out the record of FavWb address(which is recent)
      begin
        if title = '' then//this is reserved just in case we need empty-title urls again.
          ListBoxItems.Add(URL)
        else
          ListBoxItems.Add(title + ' ' + URL);
        AddressListUrls.Add(URL);
      end;
    end;
  end;
  Form1.ListBox1.Items.Text := ListBoxItems.Text;
  ListBoxItems.Free;
end;

// ==============================================================================
// FavIcon Functions
// ==============================================================================

// Copied from internet: "Imagelist with alpha blend icons loses Transparency"
// However it crashes.
// Fixed by disabling "FreeLibrary(h)"
// The DLL file is needed later, so don't free it.
// "ImageList_Create_V6" in "comctl32 v6 activation context for kobik" also does not free the loaded DLL.
function ImageList_Create_V6(CX, CY: Integer; Flags: UINT;
  Initial, Grow: Integer): HIMAGELIST;
var
  h: HMODULE;
  _ImageList_Create: function(CX, CY: Integer; Flags: UINT;
    Initial, Grow: Integer): HIMAGELIST;
stdcall;
begin
  // TODO: find comctl32.dll v6 path programmatically
  h := LoadLibrary('comctl32.dll'); // changed.
  // "ImageList_Create_V6" in "comctl32 v6 activation context for kobik" - comctllib := LoadLibrary('comctl32.dll');
  // Experiment shows this works. (no directory for 'comctl32.dll')
  //

  if h <> 0 then
    try
      _ImageList_Create := GetProcAddress(h, 'ImageList_Create');
      if Assigned(_ImageList_Create) then
        Result := _ImageList_Create(CX, CY, Flags, Initial, Grow);
    finally ; // FreeLibrary(h);//changed
    end;
end;
// ==============================================================================
// Form Component Events
// ==============================================================================

procedure TBrowserMainForm.GoButtonClick(Sender: TObject);
begin
  wb[RzTabControl1.TabIndex].Navigate(Edit1.Text);
end;

procedure TBrowserMainForm.RzTabControl1Change(Sender: TObject);
var
  i: Integer;
begin
  UpdateAddressBar := true;
  if (RzTabControl1.TabIndex = RzTabControl1.Tabs.Count - 1) and
    (RzTabControl1.Tabs[RzTabControl1.TabIndex].Caption = '+') then
  begin
    NewTab(NewTabUrl, false);
    //
    //
    // NewTab('javascript:alert(1);',false);
    // this is for testing wb_recycle:
    // it does not change location of wb_recycle
    //
    //
    Exit;
  end;

  wb[RzTabControl1.TabIndex].Show();
  for i := 0 to RzTabControl1.Tabs.Count - 1 - 1 do
    if i<>RzTabControl1.TabIndex then
      wb[i].Hide();
end;

procedure TBrowserMainForm.RzTabControl1Close(Sender: TObject;
  var AllowClose: Boolean);
var
  index: Integer;
  i: Integer;
  d: Variant;
begin
  // NOTE: If all browser tabs are closed, the "+" tab is selected active
  // then, a new tab will be created.

  if (RzTabControl1.TabIndex = RzTabControl1.Tabs.Count - 1) and
    (RzTabControl1.Tabs[RzTabControl1.TabIndex].Caption = '+') then
  begin
    Exit;
  end;

  index := RzTabControl1.TabIndex;

  wb[index].Hide;
  wb[index].Destroy; //.Free // SERIOUS PROBLEM: TEmbeddedWb.Free will crash the app, however, TWebBrowser from ShDocVw_TLB does not crash so far.

  for i := index + 1 to wb_count - 1 do
    wb[i - 1] := wb[i];
  wb_count := wb_count - 1;
  RzTabControl1.Tabs.Delete(index);

  // select the next tab, whose index is now 'index' variable
  if index < RzTabControl1.Tabs.Count - 1 then
    RzTabControl1.TabIndex := index;
end;



procedure TBrowserMainForm.Timer2Timer(Sender: TObject);
var
  d: Variant;
  s: String;
  CurrentUrl:String;
begin
  if NewTab_IsWorking then exit;

  if (UpdateAddressBar) then
  begin
    //only update address when there is new address in browser
    //so user can paste in address by mouse
    //(on contrary, always updating can't do this)
    if UpdatedAddress = wb[RzTabControl1.TabIndex].LocationURL then exit;
    CurrentUrl := wb[RzTabControl1.TabIndex].LocationURL;
    if (wb[RzTabControl1.TabIndex].LocationURL = 'about:blank')
       or (Pos('http://auxbrowser.com/BrowserObjects/',CurrentUrl)=1) then
      Edit1.Text := ''
    else
      Edit1.Text := wb[RzTabControl1.TabIndex].LocationURL;
    UpdatedAddress := wb[RzTabControl1.TabIndex].LocationURL;
  end;
end;

procedure TBrowserMainForm.ResizeWb();
var
r:TRect;
i:Integer;
begin
r := RzTabControl1.DisplayRect;
for i := 0 to wb_count - 1 do
  Windows.MoveWindow(wb[i].WbHWND,r.Left,r.Top,r.Right-r.Left,r.Bottom-r.Top,false);
end;
procedure TBrowserMainForm.FormResize(Sender: TObject);
begin
  if IsStartMaximized then
  begin
    IsStartMaximized := false;
    MoveWindow(Form1.Handle, FormRect.Left, FormRect.Top,
      FormRect.right - FormRect.Left, FormRect.Bottom - FormRect.Top, true);
  end;
  ResizeStuff();
  ResizeWb();
  if IsAddressListShown then
  begin
    IsAddressListShown := false; // necessary for ShowAddressList to work.
    ShowAddressList;
  end;
end;

procedure TBrowserMainForm.Button1Click(Sender: TObject);
begin
  wb[RzTabControl1.TabIndex].GoBack;
end;

procedure TBrowserMainForm.Button3Click(Sender: TObject);
begin
  wb[RzTabControl1.TabIndex].GoForward
end;

procedure TBrowserMainForm.Button4Click(Sender: TObject);
begin
  wb[RzTabControl1.TabIndex].Refresh;
end;

procedure TBrowserMainForm.CheckBox1Click(Sender: TObject);
begin
UpdateFavHtml();
end;

procedure TBrowserMainForm.Timer1Timer(Sender: TObject);
var
  i: Integer;
  NewCaption: WideString;
  MaxCaptionLength: Integer;
  d: Variant;
begin
  if NewTab_IsWorking then exit;

  //Timer1.Enabled := false;

  //update "Form1.Caption" and "Application.title"
  try
    {d := wb[RzTabControl1.TabIndex].Document;}
    NewCaption := wb[RzTabControl1.TabIndex].GetTitle;
  except
    NewCaption := wb[RzTabControl1.TabIndex].LocationURL;
  end;
  if NewCaption = '' then
    NewCaption := BrowserName
  else
    NewCaption := NewCaption + ' - ' + BrowserName;
  if NewCaption <> UpdatedFormCaption then
  begin
    Form1.Caption := NewCaption;
    Application.title := NewCaption;
    UpdatedFormCaption := NewCaption;
  end;

  //update RzTabControl1.Tabs[i].Caption
  MaxCaptionLength := 30;
  for i := 0 to wb_count - 1 do
  begin
    try
      NewCaption := wb[i].GetTitle;
    except
      NewCaption := wb[i].LocationURL;
    end;
    if (length(NewCaption) > MaxCaptionLength) then
    begin
      NewCaption := Copy(NewCaption, 0, MaxCaptionLength - 4) + ' ...';
    end;
    if RzTabControl1.Tabs[i].Caption <> NewCaption then
      RzTabControl1.Tabs[i].Caption := NewCaption;
  end;
end;

procedure TBrowserMainForm.BitBtn1Click(Sender: TObject);
begin
  try
    wb[RzTabControl1.TabIndex].GoBack;
  except
    ;
  end;
end;

procedure TBrowserMainForm.BitBtn2Click(Sender: TObject);
begin
  try
    wb[RzTabControl1.TabIndex].GoForward;
  except
    ;
  end;
end;

procedure TBrowserMainForm.BitBtn3Click(Sender: TObject);
begin
  try
    wb[RzTabControl1.TabIndex].Refresh;
  except
    ;
  end;
end;

procedure TBrowserMainForm.BitBtn4Click(Sender: TObject);
begin
  // NavUrl:
  // set to edit text upon mouse down event of this button
  // used for navigation in this onclick event.
  // Why?
  // mouse down on this button, then this button has focus,
  // then UpdateAddressBar is set to "true"(Timer7 checking with "GetFocus()"),
  // before mouse up on this button, address edit is updated and user input is lost.
  // NavUrl saves it before all this happens.
  HideAddressList();
  try
    // ShowMessage(NavUrl);
    wb[RzTabControl1.TabIndex].Navigate(NavUrl);
    UpdateAddressBar := true;
  except
    ;
  end;
end;

procedure TBrowserMainForm.Timer3Timer(Sender: TObject);
begin
  ShowStopOrRefreshButton();
end;

procedure TBrowserMainForm.BitBtn5Click(Sender: TObject);
begin
  try
    wb[RzTabControl1.TabIndex].Stop;
  except
    ;
  end;
end;

procedure TBrowserMainForm.BitBtn6Click(Sender: TObject);
var
  d: Variant;
  URL, title: String;
begin
  Panel2.Hide;
  RepaintStuff();
  try
    {d := wb[RzTabControl1.TabIndex].Document};
    // d.parentWindow.execScript('window.external.AddFavorite(location.href, document.title);');
    // The above does not work any more.
    //
    URL := wb[RzTabControl1.TabIndex].LocationURL;
    title := wb[RzTabControl1.TabIndex].GetTitle;
  except
    ;
  end;
  FavWb.AddToFavorites(URL, title);
end;

procedure TBrowserMainForm.BitBtn6MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
var
  d: Variant;
begin
  if Panel1.Visible = true then
    Exit;
  // fix: sometimes both favwb and panel1 is shown - move mouse across the corner of fav button(from ... button)
  // this "if" statement makes sure FavWb is not shown if Panel1 is shown.
  //
  //

  // check FavObject
  if IsFavObjectReady = false then
  begin
    InitFavObject;
    Exit;
  end;

  if (IsFavWbJustDisplayed = false) then // fix: DisplayWindow only when it's not shown - IsFavWbJustDisplayed=false
  begin
    Form1.Panel2.Show;
    Form1.FavWb.Show;
    d := Form1.FavWb.Document;
    d.parentWindow.focus();
    IsFavWbJustDisplayed := true;
  end;

  Timer4.Enabled := true;
end;

procedure TBrowserMainForm.Timer4Timer(Sender: TObject);
begin
  // By default this timer is disabled.
  // It is enabled by BitBtn6MouseMove - mouse over the fav button
  // It is then disabled upon hiding the fav list, in HandleFavObject
  if not IsCursorOnEitherObject(Form1.BitBtn6.Handle, Form1.Panel2.Handle) then
  begin
    Form1.Timer4.Enabled := false;
    Form1.Panel2.Hide;
    //
    //
    // The following "Repaint" calls are necessary. Without them, sometimes shadow line of FavWb remains after FavWb is hidden.
    RepaintStuff();

    IsFavWbJustDisplayed := false;
  end;
end;

procedure TBrowserMainForm.GetMinMaxInfo(var Msg: TWMGETMINMAXINFO);
begin
  Msg.MinMaxInfo.ptMaxSize.X := Screen.WorkAreaWidth * 2;
  Msg.MinMaxInfo.ptMaxSize.Y := Screen.WorkAreaHeight * 2;
  Msg.MinMaxInfo.ptMaxTrackSize.X := Screen.WorkAreaWidth * 2;
  Msg.MinMaxInfo.ptMaxTrackSize.Y := Screen.WorkAreaHeight * 2;
  Msg.MinMaxInfo.ptMinTrackSize.X := 0;
  Msg.MinMaxInfo.ptMinTrackSize.Y := 0;
  if IsToMakeMaxWindowOutOfScreen then
  begin
    with Msg.MinMaxInfo^ do
    begin
    ptMaxPosition.X := Screen.WorkAreaLeft + Screen.WorkAreaWidth*2;
    ptMaxPosition.Y := Screen.WorkAreaTop + Screen.WorkAreaHeight*2;
    end;
  end;
end;

procedure SetFormSize();
begin
  // "4" is the value of Windows XP which suits vclskin.
  Form1.Width := Screen.WorkAreaWidth + 8;
  Form1.Height := Screen.WorkAreaHeight + 8;
end;
procedure SetFormPos();
begin
  // "4" is the value of Windows XP which suits vclskin.
  Form1.Left := Screen.WorkAreaLeft - 4;
  Form1.Top := Screen.WorkAreaTop - 4;
end;
procedure SetFormRect();
begin
  SetFormPos();
  SetFormSize();
end;
//==============================================================================
//Set up Panel Text
//==============================================================================
procedure SetupPanel1Text();
var
distance:Integer;
begin
//The distance between labels, and the distance between label and border of panel.
distance := 8;

//The first line of menu
Form1.Label1.Caption := res.GetText('saveas');
Form1.Label1.Top := distance;
Form1.Label1.Left := distance;

Form1.Label2.Caption := res.GetText('print');
Form1.Label2.Left := Form1.Label1.Left+Form1.Label1.Width+distance;
FOrm1.Label2.Top := Form1.Label1.Top;

Form1.Label5.Caption := res.GetText('open');
Form1.Label5.Left := Form1.Label2.Left+Form1.Label2.Width+distance;
FOrm1.Label5.Top := Form1.Label2.Top;
Form1.Panel1.Width := Form1.Label5.Left+Form1.Label5.Width+distance;

//The second line of menu
Form1.Label9.Caption := res.GetText('find');
Form1.Label9.Left := distance;
Form1.Label9.Top := Form1.Label1.Top + Form1.Label1.Height + distance;

Form1.Label6.Caption := res.GetText('zoomin');
Form1.Label6.Left := Form1.Label9.Left+Form1.Label9.Width+distance;
FOrm1.Label6.Top := Form1.Label9.Top;

Form1.Label7.Caption := res.GetText('zoomout');
Form1.Label7.Left := Form1.Label6.Left+Form1.Label6.Width+distance;
FOrm1.Label7.Top := Form1.Label6.Top;

Form1.Label8.Caption := res.GetText('normalsize');
Form1.Label8.Left := Form1.Label7.Left+Form1.Label7.Width+distance;
Form1.Label8.Top := Form1.Label7.Top;
if (Form1.Panel1.Width < Form1.Label8.Left+Form1.Label8.Width+distance) then
  Form1.Panel1.Width := Form1.Label8.Left+Form1.Label8.Width+distance;

//The third line of menu
Form1.Label10.Caption := res.GetText('organizefavorites');
Form1.Label10.Left := distance;
Form1.Label10.Top := Form1.Label9.Top + Form1.Label9.Height + distance;

Form1.Label11.Caption := res.GetText('importexport');
Form1.Label11.Left := Form1.Label10.Left+Form1.Label10.Width+distance;
Form1.Label11.Top := Form1.Label10.Top;
if (Form1.Panel1.Width < Form1.Label11.Left+Form1.Label11.Width+distance) then
  Form1.Panel1.Width := Form1.Label11.Left+Form1.Label11.Width+distance;

//The forth line of menu
Form1.Label12.Caption := res.GetText('settings');
Form1.Label12.Left := distance;
Form1.Label12.Top := Form1.Label10.Top + Form1.Label10.Height + distance;

Form1.Label3.Caption := res.GetText('help');
Form1.Label3.Left := Form1.Label12.Left+Form1.Label12.Width+distance;
Form1.Label3.Top := Form1.Label12.Top;

Form1.Label4.Caption := res.GetText('about');
Form1.Label4.Left := Form1.Label3.Left+Form1.Label3.Width+distance;
Form1.Label4.Top := Form1.Label3.Top;
if (Form1.Panel1.Width < Form1.Label4.Left+Form1.Label4.Width+distance) then
  Form1.Panel1.Width := Form1.Label4.Left+Form1.Label4.Width+distance;

//The fifth line of menu
Form1.Label13.Caption := res.GetText('exit');
Form1.Label13.Left := distance;
Form1.Label13.Top := Form1.Label12.Top + Form1.Label12.Height + distance;
Form1.Label17.Caption := res.GetText('deletehistory');
Form1.Label17.Left := Form1.Label13.Left + Form1.Label13.Width + distance;
Form1.Label17.Top := Form1.Label13.Top;
if (Form1.Panel1.Width < Form1.Label17.Left+Form1.Label17.Width+distance) then
  Form1.Panel1.Width := Form1.Label17.Left+Form1.Label17.Width+distance;

Form1.Panel1.Height := Form1.Label17.Top + Form1.Label17.Height + distance;

end;

procedure SetupPanel2Text();
begin
  Form1.CheckBox1.Caption := res.GetText('sortbytime');
  Form1.Edit2.Text := res.GetText('search');
  Form1.Label14.Caption := res.GetText('clear');
  //position and size is handled in ResizeFavWb
end;

procedure SetupPanel4Text();
var
distance:Integer;
begin
distance := 8;

Form1.Label18.Caption := res.GetText('deletesessionhistory');
Form1.Label18.Left := distance;
Form1.Label18.Top := distance;
Form1.Panel4.Width := Form1.Label18.Width + distance*2;

Form1.Label19.Caption := res.GetText('deletehourhistory');
Form1.Label19.Left := distance;
Form1.Label19.Top := Form1.Label18.Top + Form1.Label18.Height + distance;
if Form1.Panel4.Width < Form1.Label19.Width + distance*2 then
  Form1.Panel4.Width := Form1.Label19.Width + distance*2;

Form1.Label23.Caption := res.GetText('deletedayhistory');
Form1.Label23.Left := distance;
Form1.Label23.Top := Form1.Label19.Top + Form1.Label19.Height + distance;
if Form1.Panel4.Width < Form1.Label23.Width + distance*2 then
  Form1.Panel4.Width := Form1.Label23.Width + distance*2;

Form1.Label20.Caption := res.GetText('deleteweekhistory');
Form1.Label20.Left := distance;
Form1.Label20.Top := Form1.Label23.Top + Form1.Label23.Height + distance;
if Form1.Panel4.Width < Form1.Label20.Width + distance*2 then
  Form1.Panel4.Width := Form1.Label20.Width + distance*2;

Form1.Edit3.Text := res.GetText('inputkeyword');
Form1.Edit3.Top := Form1.Label20.Top + Form1.Label20.Height + distance;
Form1.Edit3.Left := distance;
//edit3 width will be set up later.

Form1.Label21.Caption := res.GetText('deletekeywordhistory');
Form1.Label21.Left := distance;
Form1.Label21.Top := Form1.Edit3.Top + Form1.Edit3.Height + distance;
if Form1.Panel4.Width < Form1.Label21.Width + distance*2 then
  Form1.Panel4.Width := Form1.Label21.Width + distance*2;

Form1.Label22.Caption := res.GetText('cancel');
Form1.Label22.Left := distance;
Form1.Label22.Top := Form1.Label21.Top + Form1.Label21.Height + distance;
if Form1.Panel4.Width < Form1.Label22.Width + distance*2 then
  Form1.Panel4.Width := Form1.Label22.Width + distance*2;

Form1.Panel4.Height := Form1.Label22.Top + Form1.Label22.Height + distance;
Form1.Edit3.Width := Form1.Panel4.Width - distance*2;

end;
//==============================================================================
//Configure Internet Explorer
//==============================================================================
procedure ConfigureIE();
begin
//By default IE control is in "compatibility mode", and websites can have problem.
//
//For example, https://github.com/ says this:
//  Please note that GitHub no longer supports Internet Explorer versions 7 or 8.
//  We recommend upgrading to the latest Internet Explorer, Google Chrome, or Firefox.
//  If you are using IE 9 or later, make sure you turn off "Compatibility View".
//Even though we are on IE 9 of Windows 7
//
//This procedure makes IE control in "IE8 Standards Mode (Forced)"
//Verified to work on IE 9 of Windows 7 - https://github.com/ no longer complains.
//Verified to work even in Sandboxie sandbox, on IE 9 of Windows 7 - https://github.com/ no longer complains.
//
//Copied from http://stackoverflow.com/questions/3959334/twebrowser-load-page-with-big-fonts
  with TRegistry.Create do
    try
      RootKey := HKEY_CURRENT_USER;
      if OpenKey('Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION', true) then
        WriteInteger('WbNode.exe', 8888);//ExtractFileName(Application.ExeName)
    finally
      Free;
    end;

  //By default there is no FEATURE_LOCALMACHINE_LOCKDOWN.
  //This could be a problem as reported by a friend.
  //Note:
  //HKEY_CURRENT_USER also works.
  //Reference:
  //http://social.msdn.microsoft.com/Forums/en-US/ieextensiondevelopment/thread/c4a06945-7591-4b0f-ae01-1fec8162cfa8/
  //http://technet.microsoft.com/en-us/library/cc782928(v=ws.10).aspx
  with TRegistry.Create do
    try
      RootKey := HKEY_CURRENT_USER;
      if OpenKey('Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_LOCALMACHINE_LOCKDOWN', true) then
        WriteInteger('WbNode.exe', 1);//ExtractFileName(Application.ExeName)
    finally
      Free;
    end;
end;

//==============================================================================
//Get Default Browser
//==============================================================================
//Source: http://www.swissdelphicenter.ch/torry/showcode.php?id=397
//Note: htmlfile\shell\open\command does not work for chrome.
function LongPathName(ShortPathName: string): string;
var
   PIDL: PItemIDList;
   Desktop: IShellFolder;
   WidePathName: WideString;
   AnsiPathName: AnsiString;
begin
   Result := ShortPathName;
   if Succeeded(SHGetDesktopFolder(Desktop)) then
   begin
     WidePathName := ShortPathName;
     if Succeeded(Desktop.ParseDisplayName(0, nil, PWideChar(WidePathName),
       ULONG(nil^), PIDL, ULONG(nil^))) then

       try
         SetLength(AnsiPathName, MAX_PATH);
         SHGetPathFromIDList(PIDL, PChar(AnsiPathName));
         Result := PChar(AnsiPathName);
       finally
         CoTaskMemFree(PIDL);
       end;
   end;
end;
function GetDefaultBrowser: TBrowserInformation;
var
   tmp: PChar;
   res: LPTSTR;
   Version: Pointer;
   VersionInformation: Pointer;
   VersionInformationSize: Integer;
   Dummy: DWORD;
begin
   tmp := StrAlloc(255);
   res := StrAlloc(255);
   Version := nil;
   try
     GetTempPath(255, tmp);
     if FileCreate(tmp + 'htmpl.htm') <> -1 then
     begin
       if FindExecutable('htmpl.htm', tmp, res) > 32 then
       begin
         Result.Name := ExtractFileName(res);
         Result.Path := LongPathName(ExtractFilePath(res));
         // Try to determine the Browser Version
         VersionInformationSize := GetFileVersionInfoSize(Res, Dummy);
         if VersionInformationSize > 0 then
         begin
           GetMem(VersionInformation, VersionInformationSize);
           GetFileVersionInfo(Res, 0, VersionInformationSize, VersionInformation);
           VerQueryValue(VersionInformation, ('StringFileInfo040904E4ProductVersion'),
             Pointer(Version), Dummy);
           if Version <> nil then
             Result.Version := PChar(Version);
           FreeMem(VersionInformation);
         end;
       end
       else
         ShowMessage('Can''t determine the executable.');
         DeleteFile(tmp + 'htmpl.htm');//removed "SysUtils."
     end
     else
       ShowMessage('Can''t create temporary file.');
   finally
     StrDispose(tmp);
     StrDispose(res);
   end;
end;

Function GetUserFromWindows: string;
//http://delphi.about.com/cs/adptips2002/a/bltip0102_3.htm
 Var
    UserName : string;
    UserNameLen : Dword;
 Begin
    UserNameLen := 255;
    SetLength(userName, UserNameLen) ;
    If GetUserName(PChar(UserName), UserNameLen) Then
      Result := Copy(UserName,1,UserNameLen - 1)
    Else
      Result := 'Unknown';
 End;

//==============================================================================
//Form OnCreate
//==============================================================================
procedure TBrowserMainForm.FormCreate(Sender: TObject);
var
  hIL: HIMAGELIST;
  icon: TIcon;
  i: Integer;
begin
  NewTab_IsWorking := true;//Starting - IsWorking=true.

  Res := TRes.Create;
  Res.SetupBrowserEmbeddedObjects;

  BrowserMainFormHandle := Handle;
  IsBrowserStarting := true;
  BrowserStartDateTime := now;
  DefaultBrowserInformation := GetDefaultBrowser;
  DefaultBrowser := DefaultBrowserInformation.Path + '\' + DefaultBrowserInformation.Name;
  //HookNewProcApi;
  //HookMouse;

  WbCenterForm := TWbCenterForm.Create(nil);
  WbParent := RzTabControl1.Handle;
  IExec := CoWbExecutiveClass.Create;
  WbExecutiveFormHandle := FindWindow('TWbExecutiveForm',nil);
  while WbExecutiveFormHandle=0 do
  begin
    Sleep(5);
    WbExecutiveFormHandle := FindWindow('TWbExecutiveForm',nil);
  end;


  IsToMakeMaxWindowOutOfScreen := false;

  //ConfigureIE; - disabled - already called when program starts.

  SetupPanel1Text;
  SetupPanel2Text;
  SetupPanel4Text;

  ImageList1.Handle := ImageList_Create_V6(ImageList1.Width, ImageList1.Height,
    ILC_COLOR32 or ILC_MASK, 0, ImageList1.AllocBy);

  // PROBLEM: Go to some website, click to login, crash.
  // FIX: IT WORKS!!! from http://stackoverflow.com/questions/8200581/twebbrowser-crashes-with-embedded-youtube-clips
  Math.SetExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow,
    exUnderflow, exPrecision]);

  TimeForWindowInit := 100;

  BrowserName := Res.BrowserName;
  NewTabUrl := Res.NewTabUrl;

  wb_count := 0;
  wb_snmax := 0;
  LoadedFavIconUrls_Count := 0;
  FavIconFile := '';

  DefaultFavIconFile := Res.DocIco;

  RzTabControl1.Tabs.Insert(RzTabControl1.Tabs.Count);
  RzTabControl1.Tabs.Items[RzTabControl1.Tabs.Count - 1].Caption := '+';

  {
  Application.ProcessMessages;//For Windows XP.
  }

  // instead of 'home', go to 'about:blank'
  // there is a timer that navigates to home
  // AFTER checking to be sure that we are online
  // FIX PROBLEM: boot, not online yet, home page is not shown.
  OnlineTestFile := '';
  if IsHide then
  begin
    //PROBLEM: a beep sound is annoying in boot. FIX: no page loaded at first.
    NewTab('nonavigation', false);
    Timer15.Enabled := true;
  end
  else
  if ParamCount >= 2 then
    NewTab(ParamStr(2), false)
  else
    NewTab('home', false);

  UpdateAddressBar := true;
  WasMouseOutOfAddress := true;
  IsNewMouseEnterAddress := false;
  SelectedAllAddress := '';

  BitBtn5.Top := BitBtn3.Top;
  BitBtn5.Left := BitBtn3.Left;
  //Be sure the stop button and the refresh button have the same size.
  {
  DisplayMessage('BitBtn5.Width='+IntToStr(BitBtn5.Width)+sLineBreak+
                 'BitBtn5.Height='+IntToStr(BitBtn5.Height)+sLineBreak+
                 'BitBtn3.Width='+IntToStr(BitBtn3.Width)+sLineBreak+
                 'BitBtn3.Height='+IntToStr(BitBtn3.Height),
                 'BitBtn5 and BitBtn3');
  }
  ShowStopOrRefreshButton();

  // SetFormRect();
  // Move window out of screen at first, then timer resizes it.
  // ShowWindow(Form1.Handle,SW_HIDE);
  MakeWindowOutOfScreen := true;

  FavWbUrlSignature := Res.Signature;

  IsInitFavObject := false;
  IsFavWbJustDisplayed := false;
  FavList := '';
  LatestFavList := TStringList.Create;
  LatestFavList.Text := '';
  FavListWithoutUrl := TStringList.Create;
  FavListWithoutUrl.Text := '';
  FavFolder := '';

  Panel2.Hide;
  InitFavObject; // Fix: initialize it upon startup.
  // This was previously done in HandleFavObject which was previously actively called by Timer4.
  // However, now, Timer4 is activated only when necessary(to save resources), so call it now.

  IsAddressListShown := true; // design-time layout made the list visible
  HideAddressList(); // hide it upon start up

  Edit1.Top := BitBtn1.Top + 1; // it is necessary to align properly
  // Edit1.Height := 0;// this doesn't work - edit1.height is determined by font size//BitBtn1.Height;

  IsSpecialKeyInAddressEdit := false;

  AddressListUrls := TStringList.Create;
  UrlRecordedInHistory := '';

  Panel1.Visible := false;
  Panel3.Hide;
  Panel4.Hide;

  icon := TIcon.Create;
  ImageList2.GetIcon(0, icon);
  with TrayIconData do
  begin
    cbSize := SizeOf(TrayIconData);
    Wnd := Handle;
    uID := 0;
    uFlags := NIF_MESSAGE + NIF_ICON + NIF_TIP;
    uCallbackMessage := WM_ICONTRAY;
    hIcon := icon.Handle; // Application.Icon.Handle;
    StrPCopy(szTip, BrowserName);
  end;
  Shell_NotifyIcon(NIM_ADD, @TrayIconData);

  Form1.Left := Screen.WorkAreaLeft+Screen.WorkAreaWidth*2;
  Form1.Top := Screen.WorkAreaTop+Screen.WorkAreaHeight*2;

  OldFavSearch := '';
  FavSearchItems := TStringList.Create;
  AllowClose := false;
  UpdatedAddress := '';
  UpdatedFormCaption := '';

  Timer11.Enabled := true;//at the end of "Create", handle form size and pos.
  Application.ProcessMessages;
end;

procedure DeleteHistory(IsDeleteAfterDateTime:boolean;DeleteAfterDateTime:TDateTime;Search:String);
var
Total,i: Integer;
ItemDateTime:TDateTime;
UrlsToDelete:TStringList;
Url,Title:String;
begin
  UrlsToDelete := TStringList.Create;
  UrlsToDelete.Clear;
  Form1.UrlHistory1.SortField := sfLastvisited;
  Form1.UrlHistory1.SearchField := seBoth;
  Form1.UrlHistory1.SortDirection := sdDescending;
  Form1.UrlHistory1.Search := '';
  Total := Form1.UrlHistory1.Enumerate();
  for i := 0 to Total - 1 do
  begin
    if IsDeleteAfterDateTime then
    begin
      ItemDateTime := PEntry(Form1.UrlHistory1.Items[i]).LastVisited;
      if ItemDateTime>=DeleteAfterDateTime then
        UrlsToDelete.Add(PEntry(Form1.UrlHistory1.Items[i]).Url);
    end
    else
    begin//keyword mode
      URL := PEntry(Form1.UrlHistory1.Items[i]).URL;
      title := PEntry(Form1.UrlHistory1.Items[i]).title;
      if (Pos(LowerCase(Search), LowerCase(URL)) > 0) or
         (Pos(LowerCase(Search), LowerCase(title)) > 0) then
         UrlsToDelete.Add(PEntry(Form1.UrlHistory1.Items[i]).Url);
    end;
  end;

  for i := 0 to UrlsToDelete.Count - 1 do
    Form1.UrlHistory1.DeleteUrl(PWideChar(UrlsToDelete[i]));

  UrlsToDelete.Free;
end;

procedure TBrowserMainForm.FormDestroy(Sender: TObject);
begin
  Shell_NotifyIcon(NIM_DELETE, @TrayIconData);
end;

procedure TBrowserMainForm.Timer5Timer(Sender: TObject);
begin
  Timer5.Enabled := false;
  UpdateFavList; //disable this, and mem use no longer increases by time.
                 //disable this, and cpu usage is zero.
  Timer5.Enabled := true;
end;

procedure TBrowserMainForm.Timer6Timer(Sender: TObject);
begin
  // This timer is disabled by default.
  // It is enabled for checking state of fav, in InitFavObject
  // Once the fav is ready, it's disabled.
  if IsFavObjectReady = false then
    Exit;
  Timer6.Enabled := false;
  UpdateFavList;
  IsInitFavObject := false;
end;

procedure TBrowserMainForm.Edit1Click(Sender: TObject);
begin
  if (SelectedAllAddress<>Edit1.Text)//new addr, then upon clicking.
     or IsNewMouseEnterAddress//first click after mouse enter
     then
  begin
    Edit1.SelectAll;
    SelectedAllAddress := Edit1.Text;
    IsNewMouseEnterAddress := false;
  end;
end;

procedure TBrowserMainForm.Timer7Timer(Sender: TObject);
begin
  if (GetFocus() <> Edit1.Handle) and (GetFocus() <> ListBox1.Handle) then
  begin
    HideAddressList();
    UpdateAddressBar := true;
    Timer7.Enabled := false;
  end;
end;

procedure TBrowserMainForm.FormActivate(Sender: TObject);
begin
//http://delphi.about.com/od/delphitips2008/qt/hide_taskbutton.htm
if IsBrowserStarting then ShowWindow(Application.Handle,SW_HIDE);
end;

procedure TBrowserMainForm.FormClick(Sender: TObject);
begin
  HideAddressList;
  UpdateAddressBar := true; // update address bar if not editing the address
end;

procedure TBrowserMainForm.CloseAllTabs();
var
i,c:Integer;
begin
NewTab_IsWorking := true;
for i := 0 to wb_count - 1 do
  wb[i].Destroy;
wb_count := 0;
c := RzTabControl1.Tabs.Count;
for i := 0 to c - 1 - 1 do//do not delete the last tab(the "+" tab).
  RzTabControl1.Tabs.Delete(0);
Application.ProcessMessages;
NewTab_IsWorking := false;
end;
procedure TBrowserMainForm.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  CanClose := AllowClose;
  if NOt AllowClose then
  begin
    Hide;
    ShowWindow(Application.Handle,SW_HIDE);//newly added.
    CloseAllTabs;
  end;
end;

procedure TBrowserMainForm.ListBox1Click(Sender: TObject);
begin
  try
    wb[RzTabControl1.TabIndex].Navigate(AddressListUrls[ListBox1.ItemIndex]);
    UpdateAddressBar := true;
  except
    ;
  end;
  HideAddressList(); // this makes selection of listbox empty, so it's invoked after getting the selected value.
end;

procedure TBrowserMainForm.RzTabControl1Click(Sender: TObject);
begin
  HideAddressList;
  UpdateAddressBar := true; // update address bar if not editing the address
end;

procedure TBrowserMainForm.Edit1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  // There are scenarios when mouse is out of address edit and address list, yet address list still needs to be displayed.
  // One scenario is this: click address edit, move mouse out, and type.
  // Old code of showing address list(onclick and on typing) and hiding address list(on losing focus) is necessary.
  //
  //
  UpdateAddressBar := false;
  if Key = VK_RETURN then
  begin
    IsSpecialKeyInAddressEdit := true;
    Key := 0; // turn off beep when pressing enter
    try
      if (ListBox1.ItemIndex >= 0) then
      begin
        wb[RzTabControl1.TabIndex].Navigate(AddressListUrls[ListBox1.ItemIndex])
      end
      else
        wb[RzTabControl1.TabIndex].Navigate(Edit1.Text);
      UpdateAddressBar := true;
    except
      ;
    end;
    HideAddressList(); // this function selects nothing in address list - it should be called after navigating
  end
  else if Key = VK_ESCAPE then
  begin
    IsSpecialKeyInAddressEdit := true;
    Key := 0; // turn off beep when pressing esc
    Edit1.Text := wb[RzTabControl1.TabIndex].LocationURL;
    Edit1.SelectAll;
    HideAddressList();
  end
  else if Key = VK_UP then
  begin
    Key := 0;
    IsSpecialKeyInAddressEdit := true;
    ShowAddressList();
    Timer7.Enabled := true;
    if (ListBox1.ItemIndex - 1 >= 0) then
      ListBox1.ItemIndex := ListBox1.ItemIndex - 1
    else
      ListBox1.ItemIndex := 0;
  end
  else if Key = VK_DOWN then
  begin
    Key := 0;
    IsSpecialKeyInAddressEdit := true;
    ShowAddressList();
    Timer7.Enabled := true;
    if (ListBox1.ItemIndex + 1 <= ListBox1.Count - 1) then
      ListBox1.ItemIndex := ListBox1.ItemIndex + 1//no selected: (-1)+1=0, the 1st.
    else
      ListBox1.ItemIndex := ListBox1.Count - 1;
  end
  else
  begin // not special keys
    ListBox1.ItemIndex := -1; // if not special char, select nothing in address list.
    IsSpecialKeyInAddressEdit := false;
    ShowAddressList();
    Timer7.Enabled := true;
  end;
end;

procedure TBrowserMainForm.Edit1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin // this KeyUp event is after Edit1.Text is updated by keystroke
  if IsSpecialKeyInAddressEdit = false then
    UpdateAddressList(Edit1.Text);
end;

procedure TBrowserMainForm.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if (Key = Char(VK_RETURN)) or (Key = Char(VK_ESCAPE)) then
    Key := #0; // no beep
end;

procedure TBrowserMainForm.FavWbBeforeNavigate2(ASender: TObject;
  const pDisp: IDispatch; var URL, Flags, TargetFrameName, PostData,
  Headers: OleVariant; var Cancel: WordBool);
begin
  if Pos(FavWbUrlSignature, URL) > 0 then
    Exit;
  wb[RzTabControl1.TabIndex].Navigate(URL);
  Cancel := true;
end;

procedure TBrowserMainForm.FavWbNewWindow3(ASender: TObject;
  var ppDisp: IDispatch; var Cancel: WordBool; dwFlags: Cardinal;
  const bstrUrlContext, bstrUrl: WideString);
begin
Cancel := true;
NewTab(bstrUrl,true);
//DisplayMessage(bstrUrl,'FavWbNewWindow3');
end;

procedure TBrowserMainForm.RzTabControl1TabOrderChange(Sender: TObject;
  OldIndex, NewIndex: Integer);
var
  w: TPWB;
  i: Integer;
begin
  if OldIndex > NewIndex then // move to the left
  begin
    w := wb[OldIndex];
    for i := OldIndex downto NewIndex + 1 do // wb[OldIndex] is empty as it's moved to NewIndex
      wb[i] := wb[i - 1];
    wb[NewIndex] := w;
  end;
  if OldIndex < NewIndex then // move to the right
  begin
    w := wb[OldIndex];
    for i := OldIndex to NewIndex - 1 do // wb[OldIndex] is empty as it's moved to NewIndex
      wb[i] := wb[i + 1];
    wb[NewIndex] := w;
  end;
end;

procedure TBrowserMainForm.RzTabControl1DragOver(Sender, Source: TObject;
  X, Y: Integer; State: TDragState; var Accept: Boolean);
begin
  // remove the new-tab tab on dragging, so moving tab won't end on the right side of new-tab tab
  if RzTabControl1.Tabs[RzTabControl1.Tabs.Count - 1].Caption = '+' then
    RzTabControl1.Tabs.Delete(RzTabControl1.Tabs.Count - 1);
end;

procedure TBrowserMainForm.RzTabControl1EndDrag(Sender, Target: TObject;
  X, Y: Integer);
begin
  // new-tab tab was deleted in RzTabControl1DragOver(in order to prevent moving to the right side of new-tab tab)
  // now since the dragging has ended, restore it.
  if RzTabControl1.Tabs[RzTabControl1.Tabs.Count - 1].Caption <> '+' then
  // this event function is sometimes called when not endrag
  begin
    RzTabControl1.Tabs.Insert(RzTabControl1.Tabs.Count);
    RzTabControl1.Tabs.Items[RzTabControl1.Tabs.Count - 1].Caption := '+';
  end;
end;

procedure TBrowserMainForm.Timer8Timer(Sender: TObject);
// this is for downloading fav icons
var
  i, j: Integer;
  URL: String;
  SlashAfterDomain: Integer;
  LoadedImageIndex: Integer;
  IsDownloadSuccessful: Boolean;
  icon: TIcon;
begin
  if NewTab_IsWorking then exit;

  Timer8.Enabled := false;
  for i := 0 to wb_count - 1 do
  begin
    URL := wb[i].LocationURL;
    if (Pos('http://', URL) = 1) or (Pos('https://', URL) = 1) then
    begin
      SlashAfterDomain := PosEx('/', URL, Pos('://', URL) + 3);
      if SlashAfterDomain = 0 then
      begin
        URL := URL + '/';
        SlashAfterDomain := length(URL);
      end;
      URL := Copy(URL, 1, SlashAfterDomain);
      URL := URL + 'favicon.ico';
      // ShowMessage(Url);
      LoadedImageIndex := -1;
      for j := 0 to LoadedFavIconUrls_Count - 1 do
        if LoadedFavIconUrls[j] = URL then
          LoadedImageIndex := j;
      if LoadedImageIndex = -1 then // then download it
      begin
        if FileExists(GetFavIconFile) then // delete old fav icon.
          DeleteFile(GetFavIconFile);
        DownloadFile(URL, GetFavIconFile); // UrlDownloadToFile ret val does not work to detect download failture, by my experiment.
        icon := TIcon.Create;
        if FileExists(GetFavIconFile) then // use FileExists to detect whether download is successful.
        begin
          try
            icon.LoadFromFile(GetFavIconFile);//sometimes it's downloaded but invalid icon.
          except
            icon.LoadFromFile(DefaultFavIconFile);
          end;
        end
        else
          icon.LoadFromFile(DefaultFavIconFile);
        try
        //DisplayMessage('0.3','');
        ImageList1.AddIcon(icon); // add it to image list
        //Go to http://msdn.microsoft.com/ and the above line will have error:
        //EOutOfResources - Out of System Resources
        //FIX: use "try"; IMPACT: msdn has default icon; IE: also shows default icon;
        //DisplayMessage('0.4','');
        except
        icon.LoadFromFile(DefaultFavIconFile);
        ImageList1.AddIcon(icon);
        end;
        icon.Free;
        // add it to LoadedFavIconUrls
        LoadedFavIconUrls_Count := LoadedFavIconUrls_Count + 1;
        LoadedFavIconUrls[LoadedFavIconUrls_Count - 1] := URL;
        RzTabControl1.Tabs[i].ImageIndex := LoadedFavIconUrls_Count - 1;
      end
      else // already loaded
      begin
        if RzTabControl1.Tabs[i].ImageIndex <> LoadedImageIndex then
          RzTabControl1.Tabs[i].ImageIndex := LoadedImageIndex;
      end;
    end;
  end;
  Timer8.Enabled := true;
end;



procedure TBrowserMainForm.FormShow(Sender: TObject);
begin
//http://delphi.about.com/od/delphitips2008/qt/hide_taskbutton.htm
if IsBrowserStarting then ShowWindow(Application.Handle,SW_HIDE);
end;

procedure TBrowserMainForm.Edit1MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  //exit;//disable this event, and edit no longer "blinks".
  Timer19.Enabled := true;
end;

procedure TBrowserMainForm.Edit2Change(Sender: TObject);
begin
if Edit2.Font.Color = clGray then Exit;//when it's gray and it's changing, it's by mutli-language init.
UpdateFavHtml;
end;

procedure TBrowserMainForm.Edit2Enter(Sender: TObject);
begin
if Edit2.Font.Color = clGray then
begin
  Edit2.Text := '';
  Edit2.Font.Color := clBlack;
end;

end;

procedure TBrowserMainForm.Edit2KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if Key = VK_ESCAPE then
 Edit2.Text := '';
end;

procedure TBrowserMainForm.Edit3Enter(Sender: TObject);
begin
if Edit3.Font.Color = clGray then
begin
  Edit3.Text := '';
  Edit3.Font.Color := clBlack;
end;
end;

procedure TBrowserMainForm.Edit3KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
if Key = VK_ESCAPE then
 Edit3.Text := '';
end;

procedure TBrowserMainForm.Timer9Timer(Sender: TObject);
begin
  if not IsCursorOnEitherObject(Edit1.Handle, ListBox1.Handle) then
  begin
    HideAddressList();
    UpdateAddressBar := true;
    Timer9.Enabled := false;
  end;
end;

procedure TBrowserMainForm.ListBox1MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  // "Select ListBox items as mouse hovers over them"
  // SOURCE: http://delphi.about.com/od/adptips2003/a/bltip1203_3.htm
  ListBox1.ItemIndex := ListBox1.ItemAtPos(Point(X, Y), true);
end;

procedure TBrowserMainForm.Button2MouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  if Panel4.Visible then exit;//do not show if panel4(delete history) is visible.
  if Panel1.Visible then exit;//do not show if panel1(menu) is already visible.

  Panel1.Top := Button2.Top + Button2.Height - 1;
  Panel1.Left := Button2.Left + Button2.Width - Panel1.Width;
  Panel1.Visible := true;
  Timer10.Enabled := true;
end;

procedure TBrowserMainForm.Timer10Timer(Sender: TObject);
begin
  // By default this timer is disabled.
  // It is enabled by Button2MouseMove - mouse over the "..." button
  // It is then disabled upon hiding the panel
  if not IsCursorOnEitherObject(Button2.Handle, Panel1.Handle) then
  begin
    Timer10.Enabled := false;
    Panel1.Visible := false;
    //
    //
    // The following "Repaint" calls are necessary. Without them, sometimes shadow line of Panel1 remains after Panel1 is hidden.
    RepaintStuff();
  end;
end;

procedure TBrowserMainForm.Button2Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  wb[RzTabControl1.TabIndex].ExecWB(OLECMDID_SAVEAS, OLECMDEXECOPT_PROMPTUSER);
  Test();
end;

procedure TBrowserMainForm.Label1Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  wb[RzTabControl1.TabIndex].ExecWB(OLECMDID_SAVEAS, OLECMDEXECOPT_PROMPTUSER);

end;



procedure TBrowserMainForm.Label21Click(Sender: TObject);
begin
  Timer16.Enabled := false;
  Panel4.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();

  if (Edit3.Font.Color = clGray)
  or (Edit3.Text = '')
  or (StringReplace(Edit3.Text , ' ', '',[rfReplaceAll, rfIgnoreCase]) = '')
  then
  begin
    //restore the keyword field to default.
    Edit3.Font.Color := clGray;
    Edit3.Text := res.GetText('inputkeyword');
    MessageBox(Handle,PChar(Res.GetText('keywordisempty')),'',MB_OK or MB_ICONWARNING);
    exit;
  end;
  DeleteHistory(false,0,Edit3.Text);

  //empty the keyword field - user might not want the keyword of deleting to stay.
  Edit3.Font.Color := clGray;
  Edit3.Text := res.GetText('inputkeyword');

end;

procedure TBrowserMainForm.Label22Click(Sender: TObject);
begin
  Timer16.Enabled := false;
  Panel4.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
end;

procedure TBrowserMainForm.Label23Click(Sender: TObject);
begin
  Timer16.Enabled := false;
  Panel4.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  DeleteHistory(true,now-1,'N/A');
end;

procedure TBrowserMainForm.Label2Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  wb[RzTabControl1.TabIndex].ExecWB(OLECMDID_PRINT, OLECMDEXECOPT_PROMPTUSER);
end;

procedure TBrowserMainForm.Label5Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  wb[RzTabControl1.TabIndex].ExecWB(OLECMDID_OPEN, OLECMDEXECOPT_PROMPTUSER);

end;

procedure TBrowserMainForm.LabelMouseEnter(Sender: TObject);
begin
  TLabel(Sender).Color := clBlue;
  //PROBLEM: Windows 7 does not support this. FIX: set Transparent to false.

  TLabel(Sender).Font.Color := clWhite;
end;

procedure TBrowserMainForm.LabelMouseLeave(Sender: TObject);
begin
  TLabel(Sender).Color := Panel1.Color;
  //PROBLEM: Windows 7 does not support this. FIX: set Transparent to false.

  TLabel(Sender).Font.Color := clBlue;
end;

procedure TBrowserMainForm.BitBtn4MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  NavUrl := Edit1.Text;
end;

procedure ShowPanel3();
var
distance:integer;
begin
  distance := 8;

  Form1.Panel3.Width := Form1.BitBtn4.Left + Form1.BitBtn4.Width - Form1.Edit1.Left;
  Form1.Panel3.Top := Form1.Edit1.Top + Form1.Edit1.Height;
  Form1.Panel3.Left := Form1.Edit1.Left;
  Form1.Panel3.Height := Form1.Label15.Height + Form1.Label16.Height + distance*3;

  Form1.Label15.Top := distance;
  Form1.Label15.Left := distance;

  Form1.Label16.Top := Form1.Label15.Top + Form1.Label15.Height + distance;
  Form1.Label16.Left := distance;

  Form1.Panel3.Show;
end;
procedure TBrowserMainForm.BitBtn4MouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
  if Panel3.Visible = true then
    Exit;
  ShowPanel3();
  Timer13.Enabled := true;
end;

procedure TBrowserMainForm.Label9Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  wb[RzTabControl1.TabIndex].ExecWB(OLECMDID_FIND, OLECMDEXECOPT_PROMPTUSER);
end;

procedure TBrowserMainForm.Label6Click(Sender: TObject);
var
  d: Variant;
begin
  //d := wb[RzTabControl1.TabIndex].Document;
  //d.parentWindow.execScript(
  //  'if(document.body.style.zoom==""){document.body.style.zoom=1.25;}else{document.body.style.zoom=parseFloat(document.body.style.zoom)+0.25;};');
  wb[RzTabControl1.TabIndex].execScript(
    'if(document.body.style.zoom==""){document.body.style.zoom=1.25;}else{document.body.style.zoom=parseFloat(document.body.style.zoom)+0.25;};');
end;

procedure TBrowserMainForm.Label7Click(Sender: TObject);
var
  d: Variant;
begin
  //d := wb[RzTabControl1.TabIndex].Document;
  //d.parentWindow.execScript(
  //  'if(document.body.style.zoom==""){document.body.style.zoom=0.75;}else{if(parseFloat(document.body.style.zoom)>0.25){document.body.style.zoom=parseFloat(document.body.style.zoom)-0.25;}};');
  wb[RzTabControl1.TabIndex].execScript(
    'if(document.body.style.zoom==""){document.body.style.zoom=0.75;}else{if(parseFloat(document.body.style.zoom)>0.25){document.body.style.zoom=parseFloat(document.body.style.zoom)-0.25;}};');
end;

procedure TBrowserMainForm.Label8Click(Sender: TObject);
var
  d: Variant;
begin
  //d := wb[RzTabControl1.TabIndex].Document;
  //d.parentWindow.execScript('document.body.style.zoom=1;');
  wb[RzTabControl1.TabIndex].execScript('document.body.style.zoom=1;');
end;

procedure TBrowserMainForm.Label11Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  FavWb.ShowImportExportFavoritesAndCookies;
end;

procedure TBrowserMainForm.Label10Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  FavWb.ShowOrganizeFavorites;
end;

procedure TBrowserMainForm.Label12Click(Sender: TObject);
var
ButtonSelected : Integer;
sl:TStringList;
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();


  ButtonSelected := MessageBox(Form1.Handle,
                               PChar(res.GetText('configoutsideornot')),
                               PChar(''),
                               MB_YESNOCANCEL Or MB_ICONQUESTION Or MB_DEFBUTTON1);
  if ButtonSelected = IDNO then
  begin
    FavWb.ShowInternetOptions;
  end;
  if ButtonSelected = IDCANCEL then
  begin
    //do nothing
    ;
  end;
  if ButtonSelected = IDYES then
  begin
    sl := TStringList.Create;
    sl.Text := 'InternetOptions';
    if FileExists(res.NewProcTxt) then DeleteFile(res.NewProcTxt);
    sl.SaveToFile(res.NewProcTxt,TEncoding.UTF8);
    sl.Free;
  end;
end;

procedure TBrowserMainForm.Label13Click(Sender: TObject);
var
i:Integer;
wbc:Integer;
sl:TStringList;
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();

  sl := TStringList.Create;
  sl.Text := 'BrowserExit';
  if FileExists(res.NewProcTxt) then DeleteFile(res.NewProcTxt);
  sl.SaveToFile(res.NewProcTxt,TEncoding.UTF8);
  sl.Free;

  Shell_NotifyIcon(NIM_DELETE, @TrayIconData);

  NewTab_IsWorking := true;
  wbc := wb_count;
  wb_count := 0;
  for i := 0 to wbc - 1 do
    wb[i].Destroy;

  PreparedWbNode.Destroy;
  IExec := nil;
  ExitProcess(0);
end;

procedure TBrowserMainForm.Label14Click(Sender: TObject);
begin
Edit2.Text := '';
end;

procedure TBrowserMainForm.Label17Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();

  Panel4.Top := Button2.Top + Button2.Height - 1;
  Panel4.Left := Button2.Left + Button2.Width - Panel4.Width;
  Panel4.Visible := true;
  Timer16.Enabled := true;
end;

procedure TBrowserMainForm.Label18Click(Sender: TObject);
begin
  Timer16.Enabled := false;
  Panel4.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  DeleteHistory(true,BrowserStartDateTime,'N/A');
end;

procedure TBrowserMainForm.Label19Click(Sender: TObject);
begin
  Timer16.Enabled := false;
  Panel4.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  DeleteHistory(true,now-(1/24),'N/A');
end;

procedure TBrowserMainForm.Label20Click(Sender: TObject);
begin
  Timer16.Enabled := false;
  Panel4.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  DeleteHistory(true,now-7,'N/A');
end;

procedure TBrowserMainForm.Label3Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  NewTab('http://auxbrowser.com/BrowserObjects/3.0.0.6/help/', false);
end;

procedure TBrowserMainForm.Label4Click(Sender: TObject);
begin
  Timer10.Enabled := false;
  Panel1.Hide;
  //
  //
  // The following "Repaint" is necessary. Without it, portions of Panel1 remain like shadow for a while, it's ugly.
  RepaintStuff();
  NewTab('http://auxbrowser.com/BrowserObjects/3.0.0.6/about/', false);
end;

procedure TBrowserMainForm.Timer11Timer(Sender: TObject);
var
Form2:TTemporaryForm;
begin
  Timer11.Enabled := false;
  Form1.Left := Screen.WorkAreaLeft + Screen.WorkAreaWidth - 1;
  // x: one pixel is shown.(right side)
  Form1.Top := Screen.WorkAreaTop - Form1.Height + 1;
  // y:one pixel is shown.(on the top)
  // Why one pixel of window is shortly displayed at the corner?
  // If it's completely out of screen, and then moved into screen, there is flash blank effect.
  // However, if it's partly displayed and then moved into screen, it's perfectly displayed and ready immediately.
  //

  //IsProgramStarting := false;
  Form1.Show;

  //Why do we display a dialog window that exists for a while?
  //By experiment I found if there is a DisplayMessage(MessageBox) call, SetFormSize(&Pos) later is ok.
  //(on Windows 7)
  //However, simple Sleep call is not okay for later SetFormSize(&Pos).
  //So we create an invisible dialog and display it for while, like DisplayMessage(MessageBox).
  Form2 := TTemporaryForm.Create(nil);
  Form2.ShowModal;
  Form2.Free;

  SetFormSize();
  Timer12.Enabled := true;
end;

procedure TBrowserMainForm.Timer12Timer(Sender: TObject);
begin
Timer12.Enabled := false;
//WaitForAllDllLoading;//not necessary.
                       //This timer is enabled at the end of timer11
                       //All DLL loading is done then.
//DisplayMessage('All DLL Loaded','');
if IsHide=false then SendMessage(Form1.Handle,WM_ICONTRAY,0,WM_LBUTTONDOWN);
end;

procedure TBrowserMainForm.Timer13Timer(Sender: TObject);
begin
  // By default this timer is disabled.
  // It is enabled by Button2MouseMove - mouse over the "..." button
  // It is then disabled upon hiding the panel
  if not IsCursorOnEitherObject(BitBtn4.Handle, Panel3.Handle) then
  begin
    Timer13.Enabled := false;
    Panel3.Visible := false;
    //
    //
    // The following "Repaint" calls are necessary. Without them, sometimes shadow line of Panel1 remains after Panel1 is hidden.
    //RepaintStuff();
  end;
end;

procedure TBrowserMainForm.Timer14Timer(Sender: TObject);
var
d:Variant;
host,protocol:String;
begin
  if NewTab_IsWorking then exit;

  host := '';
  protocol := '';
  try
    //d:= wb[RzTabControl1.TabIndex].Document;
    //host := d.location.host;
    //protocol := d.location.protocol;
    host := wb[RzTabControl1.TabIndex].GetHost;
    protocol := wb[RzTabControl1.TabIndex].GetProtocol;
  except//Changed from "finally" to "except" - this fixed some exception message box.
    ;
  end;
  protocol := LowerCase(protocol);
  protocol := StringReplace(protocol, ':', '',[rfReplaceAll, rfIgnoreCase]);
  if host = '' then host := 'N/A';
  if protocol = '' then protocol := 'N/A';

  Label15.Caption := Res.GetText('currentdomain')+host;

  if protocol = 'https' then
    Label16.Caption := Res.GetText('currentprotocol')+protocol+' - '+Res.GetText('encryptedhttps')
  else
    Label16.Caption := Res.GetText('currentprotocol')+protocol+' - '+Res.GetText('notencryptedhttps');
end;

function GetOnlineTestFile(): String;
var
  length: DWORD;
  TempPath: string;
begin
  if OnlineTestFile <> '' then
  begin
    Result := OnlineTestFile;
    Exit;
  end;
  SetLength(TempPath, MAX_PATH);
  length := GetTempPath(MAX_PATH, PChar(TempPath));
  SetLength(TempPath, length);
  //PROBLEM FIX: on Windows XP long file name does not work. short file name works.
  OnlineTestFile := TempPath + 'dltest.txt'; // TempPath ends with slash
  Result := OnlineTestFile;
  // ShowMessage(Result);
end;
function WaitUntilOnlineThenGoHome_Thread(Parameter : Pointer) : Integer;
var
OnlineTestUrl:String;
d:Variant;
s:String;
begin
//reference: http://www.delphibasics.co.uk/RTL.asp?Name=BeginThread
Result := 0;
OnlineTestUrl := 'http://www.google.com/robots.txt';
if FileExists(GetOnlineTestFile) then
  DeleteFile(GetOnlineTestFile);
DownloadFile(OnlineTestUrl, GetOnlineTestFile); // UrlDownloadToFile ret val does not work
while (not FileExists(GetOnlineTestFile)) do //wait until download succeeds.
begin
  DownloadFile(OnlineTestUrl, GetOnlineTestFile); // UrlDownloadToFile ret val does not work
  Sleep(100);
end;
DeleteFile(GetOnlineTestFile);
//DisplayMessage('Now we are online!','');
//if this first tab is not blank, then user already navigated.
s := '';
try
s := wb[0].LocationURL;
except
s := '';
end;
//DisplayMessage('"'+s+'"','s');
//'nonavigation' tab has 's' equal to empty string.
if s='' then
  wb[0].GoHome;
EndThread(0);
end;
procedure TBrowserMainForm.Timer15Timer(Sender: TObject);
var
id1: LongWord;
thread1: Integer;
begin
if NewTab_IsWorking then exit;

//disabled by default
//only enabled if it's boot - IsHide=true
//wait for being online and then navigate the first tab to home.
Timer15.Enabled := false;
//must do this in another thread, otherwise the form freezes.
thread1 := BeginThread(nil,0,Addr(WaitUntilOnlineThenGoHome_Thread),nil,0,id1);
end;

procedure TBrowserMainForm.Timer16Timer(Sender: TObject);
begin
  // By default this timer is disabled.
  // It is enabled by showing panel4 in "Delete Records in History"
  // It is then disabled upon hiding the panel
  if not IsCursorOnEitherObject(Button2.Handle, Panel4.Handle) then
  begin
    Timer16.Enabled := false;
    Panel4.Visible := false;
    //
    //
    // The following "Repaint" calls are necessary. Without them, sometimes shadow line of Panel1 remains after Panel1 is hidden.
    RepaintStuff();
  end;
end;

procedure TBrowserMainForm.Timer17Timer(Sender: TObject);
begin
Timer17.Enabled := false;
NewTab(NewTabTxtContent,true);
end;

procedure TBrowserMainForm.Timer18Timer(Sender: TObject);
begin
if not IsCursorOnEitherObject(Edit1.Handle, Edit1.Handle) then
begin
  WasMouseOutOfAddress := true;
  IsNewMouseEnterAddress := false;
  Timer18.Enabled := false;
end;
end;

procedure TBrowserMainForm.Timer19Timer(Sender: TObject);
begin
  Timer19.Enabled := false;
  if (not IsAddressListShown) and WasMouseOutOfAddress then
  begin
    UpdateAddressList('');
    ShowAddressList();
    Timer9.Enabled := true;
  end;
  if WasMouseOutOfAddress then
  begin
    WasMouseOutOfAddress := false;//already in address, any further mouse move is not entering.
    IsNewMouseEnterAddress := true;
    Timer18.Enabled := true;
  end;
end;

procedure TBrowserMainForm.Timer20Timer(Sender: TObject);
begin
Timer20.Enabled := false;
wb[RzTabControl1.TabIndex].Repaint;//newly added.
Application.ProcessMessages;//newly added. //Sleep(100);
SetFormPos();
{
ResizeWb();//for Windows XP
RzTabControl1.Repaint;//for Windows XP
}
Application.ProcessMessages;//newly added. //Sleep(100);
Timer21.Enabled := true;
end;
procedure TBrowserMainForm.Timer21Timer(Sender: TObject);
begin
Timer21.Enabled := false;
ResizeWb();
RzTabControl1.Repaint;
end;

procedure SetNormalWindowPlacementOutOfScreen();
var
  Wp: TWindowPlacement;
begin
//http://stackoverflow.com/questions/1194932/saving-the-maximized-and-form-size-on-a-delphi-tform
Wp.length := SizeOf(TWindowPlacement);
GetWindowPlacement(Form1.Handle, @Wp);

Wp.rcNormalPosition.Left := Screen.WorkAreaLeft + Screen.WorkAreaWidth*2;
Wp.rcNormalPosition.Top := Screen.WorkAreaTop + Screen.WorkAreaHeight*2;
Wp.rcNormalPosition.Right := Wp.rcNormalPosition.Left + 1;
Wp.rcNormalPosition.Bottom := Wp.rcNormalPosition.Top + 1;
Wp.showCmd := SW_SHOWNORMAL;
//Wp.rcNormalPosition.Right := Form1.Left+Form1.Width;
//Wp.rcNormalPosition.Bottom := Form1.Top+Form1.Height;
SetWindowPlacement(Form1.Handle, @Wp);
end;

procedure TBrowserMainForm.TrayMessage(var Msg: TMessage);
var
s:String;
sl:TStringList;
begin
  case Msg.lParam of
    WM_LBUTTONDOWN:
      begin
          //handle newtab.txt first. later code can take some time.
          //By then, newtab.txt might have been deleted.
          NewTabTxtContent := '';
          if FileExists(res.NewTabTxt) then
          begin
              sl := TStringList.Create;
              sl.LoadFromFile(res.NewTabTxt,TEncoding.UTF8);
              s := sl.Text;
              sl.Free;
              NewTabTxtContent := s;
              //Problem: "NewTab(s,true)" causes error.
              //Fix: In the end we do this: "Timer17.Enabled := true"(run NewTab)
              //     Of course we check before NewTab ... if NewTabTxtContent <> ''
          end;
          //Now we are going to display the main form on screen.
          //We move window out of screen, do our stuff, then move window into screen.
          //Timer20 moves window into screen.
          //Before timer20, we handle IsZoomed(maximized) and IsIconic(minimized).
          //Also we use "IsToMakeMaxWindowOutOfScreen" to make maximized out of screen(MINMAXINFO).
          IsBrowserStarting := false;
          if IsZoomed(Form1.Handle)
            and (not IsIconic(Application.Handle))
            and (not Visible) then
          begin
              IsToMakeMaxWindowOutOfScreen := true;
              Visible:= true;
              Application.ProcessMessages;
              IsToMakeMaxWindowOutOfScreen := false;
          end;
          SetFormSize();
          Form1.Left := Screen.WorkAreaLeft + Screen.WorkAreaWidth - 1;
          Form1.Top := Screen.WorkAreaTop - Form1.Height + 1;
          if IsIconic(Application.Handle) and IsZoomed(Form1.Handle) then
          begin
            IsToMakeMaxWindowOutOfScreen := true;
            ShowWindow(Application.Handle,SW_SHOWNORMAL);
            Application.ProcessMessages;
            IsToMakeMaxWindowOutOfScreen := false;
            SetFormSize;
            Application.ProcessMessages;
          end
          else
          begin
            if IsIconic(Application.Handle) then//minimize Application.handle - http://stackoverflow.com/questions/6303621/proper-handling-of-modal-window-minimize-behavior
            begin
              ShowWindow(Application.Handle,SW_SHOWNORMAL);
            end;
            if IsZoomed(Form1.Handle) then
            begin
              SetNormalWindowPlacementOutOfScreen;//weird here.
              Form1.WindowState := wsNormal;//ShowWindow(Form1.Handle,SW_SHOWNORMAL);
              SetFormSize;
              Application.ProcessMessages;
            end;
          end;
          ForceForegroundWindow(Form1.Handle);
          Form1.Show;
          ShowWindow(Application.Handle,SW_SHOW);
          Application.ProcessMessages;//newly added.
          {Form1.Width := Form1.Width - 1;//For Windows XP.
          Sleep(5);                      //For Windows XP.
          Form1.Width := Form1.Width + 1;//For Windows XP.}
          Form1.Invalidate; //newly added.
          Application.ProcessMessages;//newly added.
          Timer20.Enabled := true;
          //Timer20 interval ... 20 ... display main form on screen("SetFormPos")
          //Timer17 interval ... 10 ... create new tab("NewTab")
          //Effect: before main form is displayed, new tab is created. This is ok.
          if NewTabTxtContent <> '' then
            Timer17.Enabled := true;//NewTab
      end;
    WM_RBUTTONDOWN:
      begin ;
      end;
  end;
end;

procedure TBrowserMainForm.WMEndSession(var Message: TWMEndSession);
begin
  //PROBLEM: This program is preventing Windows from shutting down
  //using solution at http://stackoverflow.com/questions/6609921/not-prevent-windows-from-shutting-down-onclosequery
  AllowClose:=true;
  Message.Result:=1;

  inherited; //using solution at http://delphi.about.com/cs/adptips2000/a/bltip0500_4.htm
end;

procedure TBrowserMainForm.WMQueryEndSession(var Msg : TWMQueryEndSession) ;
begin
//PROBLEM: This program is preventing Windows from shutting down
//using solution at http://delphi.about.com/cs/adptips2000/a/bltip0500_4.htm
   Msg.Result := 1 ;
end;

procedure TBrowserMainForm.WMCopyData(var Msg : TWMCopyData) ;
var
s : string;
sl:TStringList;
wb_index,i:Integer;
begin
s := PChar(Msg.CopyDataStruct.lpData) ;
sl := TStringList.Create;
sl.Text := s;

if sl.Strings[0] = 'NewWindow2' then
begin
//DisplayMessage('TBrowserMainForm.WMCopyData NewWindow2','');
wb_count := wb_count + 1;
wb_index := Form1.RzTabControl1.TabIndex + 1;
for i := wb_count - 1 downto wb_index + 1 do
  wb[i] := wb[i - 1];
Form1.RzTabControl1.Tabs.Insert(wb_index);
Form1.RzTabControl1.Tabs.Items[wb_index].Caption := ' ';

wb[wb_index] := PreparedWbNode;
PreparedWbNode := nil;

ResizeWb;
for i := 0 to wb_count - 1 do
  wb[i].Hide();
wb[wb_index].Show;
RzTabControl1.TabIndex := wb_index;
end
else if sl.Strings[0] = 'TitleChanged' then
begin
RecordTitleInHistory(StrToInt(sl.Strings[1]));
{
//This piece of code is disabled because:
//What happens if "timer" code is executing,
//and we execute it right here at the same time.
//The result will be a mess.
Timer1Timer(nil);//update title
Timer2Timer(nil);//update address
Timer8Timer(nil);//update favicon
Timer3Timer(nil);//update stop/refresh button
Timer14Timer(nil);//update domain and protocol panel
}
end;


sl.Free
end;
end.
